Introduction
In this first tutorial, we are going to learn the basics on how to make calls to a Web Api Rest Service using the NuGet Package WebApiRestService.WebApiClient.
What is WebApiClient?
WebApiClient is a simple and powerful .NET Portable Library built to work as a middle layer between your application and a RESTFul service, like the Microsoft WebApi. It provides methods to make asynchronous, typed WebApi requests using the HttpClient class. It takes care of all the logic to create the request, wait for the response, handle exceptions and convert the response into an object, leaving you free of writing repetitive code.
Features
- It is portable. Supports .NET Framework 4.5+, Windows 8+ Apps, Windows Phone Silverlight 8+
- Supports any kind of RESTful service, not only Microsoft WebApi
- Ready to work with services that use ASP.NET Identity security
- Easy installation using NugGet
- Supports Json and Xml serialization/deserialization
- Supports the verbs GET, POST, PUT and DELETE
- Easy to extend functionalities
- Comes with WindowsIntegratedAuthentication (Negotiate, NTLM, Basic, Kerberos) and BearerTokenAuthentication
- Easy to send or receive cookies
Resources
You can find more info and examples at: http://webapiclient.azurewebsites.net
To download the NuGet Package: https://www.nuget.org/packages/WebApiRestService.WebApiClient
Using the code
First of all, you need to set up a solution, containing at least 3 projects:
- A WebApi Project
- A MVC project (the project type you'll choose is up to you)
- A Class Library Project, to accomodate the DTO objects
In the Class Library Project
- create the following class:
public class Restaurant
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
In the WebApi Project
- add a reference to the DTO Class Library Project you just created in the last step.
- create a controller called RestaurantController, and paste this class:
public class RestaurantController : ApiController
{
List<Restaurant> restaurants = new List<Restaurant>() {
new Restaurant(){ Id = 1, Name = "Restaurant 1", Address = "1111 Oxford Street" },
new Restaurant(){ Id = 2, Name = "Restaurant 2", Address = "2222 Oxford Street" },
new Restaurant(){ Id = 3, Name = "Restaurant 3", Address = "3333 Oxford Street" },
new Restaurant(){ Id = 4, Name = "Restaurant 4", Address = "4444 Oxford Street" }
};
public IEnumerable<Restaurant> Get()
{
return restaurants;
}
public Restaurant Get(int id)
{
return restaurants.SingleOrDefault(r => r.Id == id);
}
public void Post([FromBody]Restaurant value)
{
restaurants.Add(value);
}
public void Put([FromBody]Restaurant value)
{
restaurants.RemoveAll(r => r.Id == value.Id);
restaurants.Add(value);
}
public void Delete(int id)
{
restaurants.RemoveAll(r => r.Id == id);
}
}
In the MVC Project
- add a reference to the DTO Class Library Project
- open the Package Manager Console and run the folowing command, to install the WebApiClient (for more details, see this and this):
Install-Package WebApiRestService.WebApiClient
- create a controller called RestaurantsController, and paste this class:
public class RestaurantsController : Controller
{
private WebApiClientOptions options =
new WebApiClientOptions("http://localhost:60214/api", "restaurant");
public async Task<ActionResult> Index()
{
List<Restaurant> list = null;
using(WebApiClient<Restaurant> client = new WebApiClient<Restaurant>(options))
{
list = await client.GetManyAsync();
}
return View(list);
}
public async Task<ActionResult> IndexOldFashioned()
{
List<Restaurant> list = null;
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:60214/api/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync("restaurant");
if (!response.IsSuccessStatusCode)
{
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
list = await response.Content.ReadAsAsync<List<Restaurant>>();
return View("Index", list);
}
public async Task<ActionResult> Details(int? id)
{
Restaurant restaurant = null;
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
using (WebApiClient<Restaurant> client = new WebApiClient<Restaurant>(options))
{
restaurant = await client.GetOneAsync(id);
}
if (restaurant == null)
{
return HttpNotFound();
}
return View(restaurant);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(Restaurant restaurant)
{
if (ModelState.IsValid)
{
using (WebApiClient<Restaurant> client = new WebApiClient<Restaurant>(options))
{
await client.CreateAsync(restaurant);
}
return RedirectToAction("Index");
}
return View(restaurant);
}
public async Task<ActionResult> Edit(int? id)
{
Restaurant restaurant = null;
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
using (WebApiClient<Restaurant> client = new WebApiClient<Restaurant>(options))
{
restaurant = await client.GetOneAsync(id);
}
if (restaurant == null)
{
return HttpNotFound();
}
return View(restaurant);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(Restaurant restaurant)
{
if (ModelState.IsValid)
{
using (WebApiClient<Restaurant> client = new WebApiClient<Restaurant>(options))
{
await client.EditAsync(restaurant);
}
return RedirectToAction("Index");
}
return View(restaurant);
}
public async Task<ActionResult> Delete(int? id)
{
Restaurant restaurant = null;
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
using (WebApiClient<Restaurant> client = new WebApiClient<Restaurant>(options))
{
restaurant = await client.GetOneAsync(id);
if (restaurant == null)
{
return HttpNotFound();
}
}
return View(restaurant);
}
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(Restaurant restaurant)
{
if (restaurant == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
using (WebApiClient<Restaurant> client = new WebApiClient<Restaurant>(options))
{
restaurant = await client.GetOneAsync(restaurant.Id);
if (restaurant == null)
{
return HttpNotFound();
}
await client.DeleteAsync(restaurant.Id);
}
return RedirectToAction("Index");
}
}
Now, you can run the MVC project, point to a URL like http://localhost:60232/restaurants/ and see the results.
As you can see in the above code, using the WebApiClient to call a RESTful service is pretty straight forward. All you need to do is create a WebApiClientOptions object, configure it as you like
private WebApiClientOptions options =
new WebApiClientOptions("http://localhost:60214/api", "restaurant");
and start using the WebApiClient object to make calls to your service. Take a look at the Index action method:
public async Task<ActionResult> Index()
{
List<Restaurant> list = null;
using(WebApiClient<Restaurant> client = new WebApiClient<Restaurant>(options))
{
list = await client.GetManyAsync();
}
return View(list);
}
If you have been using the the HttpClient so far, take a look at the next action method... you should be writing something like this:
public async Task<ActionResult> IndexOldFashioned()
{
List<Restaurant> list = null;
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:60214/api/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/json"));
var response = await client.GetAsync("restaurant");
if (!response.IsSuccessStatusCode)
{
return new HttpStatusCodeResult(HttpStatusCode.InternalServerError);
}
list = await response.Content.ReadAsAsync<List<Restaurant>>();
return View("Index", list);
}
Now, if you compare these two different action methods you will probably see that the conventional method (using HttpClient) is much more difficult to read and maintain than that one using the WebApiClient. When you add more configuration like Authentication, the code becomes even more complex.
Other Features
The WebApiClient Library has a bunch of other features that will be covered in the next tutorials:
- Authentication
- Cookies
- Inheritance
- Exception Handling
- Threads
- Timeouts