Contents
- Abstract
- Introduction
- Background
- Pre-requisites
- Why RestSharp
- What we consume
- Create the Web Project
- Add RestSharp Support to Project
- Add Rest Client
- Create Model Class
- Describing Model Class
- Why All the Checks Are On the Client Side
- Create Controller
- Describing Controller
- Create View
- Executing the Project
- Closing Notes
Abstract
Throughout the article we will learn how to call APIs hosted on another server (as a REST services only) from ASP.NET MVC4 (as a client) using RESTSHARP.
Introduction
In most scenarios, we develop an application of ASP.NET MVC4 using the ASP.NET WEB API. But a RESTFul service like the ASP.NET WEB API is meant to be used by various clients. In this article we will see how to consume a simple ASP.NET WEB API using ASP.NET MVC4 (as a client) with RestSharp (simple Rest and HTTP client for .Net).
Background
Before going through this article, I recommend your read my previous article where I defined how to create an ASP.NET WEB API (CRUD Operations using Fluent NHibernate).
Prerequisites
To implement and play with the source code one should have:
- Visual Studio 2013 Express or later
- ASP.NET MVC4 or later
- ASP.NET WEB API2 or later
- Basic knowledge of RestFul Services
- Basic knowledge of ASP.NET WEB API
- Basic knowledge of ASP.NET MVC4 or later
Why RestSharp
Since we will use RestSharp to call our ASP.NET WEB API URIs, first let's discuss "RestSharp". This is nothing but a Simple REST and HTTP API Client for .NET. It provides us a simple way to just initialize a RestClient, pass a Request, define a Method (GET, POST, PUT, DELETE) and get a response.
The followings shows a commonly used snippet:
-
- RestClient restClient = RestClient("url");
-
- var request = new RestRequest("api/serverdata", Method.GET);
Do not forget to provide RequestFormat and RestSharp to automatically serialize/deserialize complex objects like Models like ServerDataModel in our demo project.
-
- var request = new RestRequest("api/serverdata", Method.GET)
- {RequestFormat = DataFormat.Json};
The following will get a formatted result for complex types:
var response = restClient.Execute<List<ServerDataModel>>(request);
There are many more features, we are not covering in this article. Please refer to RestSharp Wiki .
What we consume
As said earlier in this article, we will consume existing ASP.NET Web API URIs (hosted on a server). The following is the table showing all the URIs:
Refer to the demo app: Demo ASP.NET WEB API.
Create the Web Project
Let's start the creation of our new ASP.NET project (client project) using the following:
Start Visual Studio and select "File" -> "New" -> "Project..." (or enter Ctrl + Shift + N).
In the Templates dialog, select Installed Templates and then expand the Visual C# node. Under Visual C#, select Web. In the list of project templates, select ASP.NET MVC4 Web Application, name the project and click "OK".
I named my project "consumewebapi", you can choose whatever you want.
From the Project Template, select Internet Application and Razor from the View Engine dropdown list and click "OK".
You can also check the "Create unit test project" checkbox if you are doing Test driven development and I highly recommend doing that. In this article, we are not covering that part.
Now, after the preceding step(s), we have a default ASP.NET MVC4 project template with us, later on we will add to it.
Add RestSharp Support to Project
We will use RestSharp to consume our ASP.NET WEB API, use this procedure:
Go to Tools -> NuGet Package Manager -> Package Manager Console.
From the Package Manager Console, run the following command:
Install-Package RestSharp
Add Rest Client
1. From Solution Explorer, create a new folder and name it Helper. This folder will contain all our helper classes required for the RestSharp client (these classes will play an interface between our client and services).
2. Add an interface and name it IServerDataRestClient.
The complete code of IServerDataRestClient looks as in:
- public interface IServerDataRestClient
- {
- void Add(ServerDataModel serverDataModel);
- void Delete(int id);
- IEnumerable<serverdatamodel> GetAll();
- ServerDataModel GetById(int id);
- ServerDataModel GetByIP(int ip);
- ServerDataModel GetByType(int type);
- void Update(ServerDataModel serverDataModel);
- }
3. Add a new class under Helper folder and name it ServerDataRestClient and implement the interface IServerDataRestClient:
- public class ServerDataRestClient : IServerDataRestClient
- {
-
- }
We need to create a RestClient, create a variable private readonly RestClient _client in the class and initialize it in the constructor.
-
- public ServerDataRestClient()
- {
- _client = new RestClient(_url);
- }
In the preceding, while we are initializing the RestClient object, we are providing a BaseUrl, nothing but the complete name of the URL like http://gaurav-arora.com
We can also do this:
- _client = new RestClient {BaseUrl = _url};
We are fetching the base URL from our config files, why it is in config files. It is recommended for large projects where we have multiple environments like Dev, Staging, QA, Prod and so on.
-
- private readonly string _url = ConfigurationManager.AppSettings["webapibaseurl"];
Now, we require a request that contains nothing but a resource and a method.
By providing {RequestFormat = DataFormat.Json}; we are telling RestClient to provide us an output in the form of JSON. This is required when working with complex classes, like here we are using the ServerDataModel class.
In DEBUG mode, check _client in Quick watch (Ctrl + D,Q). You will find everything we set when we created our RestClient object.
Our client is ready to convey our request and get the response.
- var response = _client.Execute<List<ServerDataModel>>(request);
The preceding will provide us the output in a list of our ServerDataModel class.
Open Quick watch for the response, you will get the following two nodes:
[RestSharp.RestResponse<System.Collections.Generic.List<ConsumeWebAPI.Models.ServerDataModel>>] {RestSharp.RestResponse<System.Collections.Generic.List<ConsumeWebAPI.Models.ServerDataModel>>} RestSharp.RestResponse<System.Collections.Generic.List<ConsumeWebAPI.Models.ServerDataModel>> and Data.
The first node contains our actual content in JSON format with other information. For example, ContentLength, ContentType, Cookies, ErrorMessage, Header, Request, ResponseStatus, StatusCode and so on.
The Data node contains our formatted data as we requested and required. In our case, it is a list of type ServerDataModel. We will use this model and our view will show later.
We can also request a specific resource like if we need record by id, then we can do:
- var request = new RestRequest("api/serverdata/{id}", Method.GET) {RequestFormat = DataFormat.Json};
-
- request.AddParameter("id", id, ParameterType.UrlSegment);
The following will provide us output of type ServerDataModel:
var response = _client.Execute<serverdatamodel>(request);
The following is our complete ServerDataRestClient helper class:
- public class ServerDataRestClient : IServerDataRestClient
- {
- private readonly RestClient _client;
- private readonly string _url = ConfigurationManager.AppSettings["webapibaseurl"];
-
- public ServerDataRestClient()
- {
- _client = new RestClient {BaseUrl = _url};
- }
-
- public IEnumerable<serverdatamodel> GetAll()
- {
- var request = new RestRequest("api/serverdata", Method.GET) {RequestFormat = DataFormat.Json};
-
- var response = _client.Execute<list<serverdatamodel>>(request);
-
- if (response.Data == null)
- throw new Exception(response.ErrorMessage);
-
- return response.Data;
- }
-
- public ServerDataModel GetById(int id)
- {
- var request = new RestRequest("api/serverdata/{id}", Method.GET) {RequestFormat = DataFormat.Json};
-
- request.AddParameter("id", id, ParameterType.UrlSegment);
-
- var response = _client.Execute<serverdatamodel>(request);
-
- if (response.Data == null)
- throw new Exception(response.ErrorMessage);
-
- return response.Data;
- }
-
- public ServerDataModel GetByType(int type)
- {
- var request = new RestRequest("api/serverdata/type/{datatype}", Method.GET)
- {
- RequestFormat = DataFormat.Json
- };
-
- request.AddParameter("datatype", type, ParameterType.UrlSegment);
-
- var response = _client.Execute<serverdatamodel>(request);
-
- return response.Data;
- }
-
- public ServerDataModel GetByIP(int ip)
- {
- var request = new RestRequest("api/serverdata/ip/{ip}", Method.GET) {RequestFormat = DataFormat.Json};
- request.AddParameter("ip", ip, ParameterType.UrlSegment);
-
- var response = _client.Execute<serverdatamodel>(request);
-
- return response.Data;
- }
-
- public void Add(ServerDataModel serverData)
- {
- var request = new RestRequest("api/serverdata", Method.POST) {RequestFormat = DataFormat.Json};
- request.AddBody(serverData);
-
- var response = _client.Execute<serverdatamodel>(request);
-
- if (response.StatusCode != HttpStatusCode.Created)
- throw new Exception(response.ErrorMessage);
- }
-
- public void Update(ServerDataModel serverData)
- {
- var request = new RestRequest("api/serverdata/{id}", Method.PUT) {RequestFormat = DataFormat.Json};
- request.AddParameter("id", serverData.Id, ParameterType.UrlSegment);
- request.AddBody(serverData);
-
- var response = _client.Execute<serverdatamodel>(request);
-
- if (response.StatusCode == HttpStatusCode.NotFound)
- throw new Exception(response.ErrorMessage);
- }
-
- public void Delete(int id)
- {
- var request = new RestRequest("api/serverdata/{id}", Method.DELETE);
- request.AddParameter("id", id, ParameterType.UrlSegment);
-
- var response = _client.Execute<serverdatamodel>(request);
-
- if (response.StatusCode == HttpStatusCode.NotFound)
- throw new Exception(response.ErrorMessage);
- }
- }
Create Model Class
Under Solution Explorer, right-click on the Models folder and Add -> New Item (or hit Ctrl + Shift + A). Choose the class and name it ServerDataModel and click "Add". It will add an empty Model class.
Here is our complete model class:
- public class ServerDataModel
- {
- public int Id { get; set; }
- [Required]
- [Display(Name = "Initial date")]
- [DataType(DataType.Date)]
- [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
- public DateTime InitialDate { get; set; }
- [Required]
- [Display(Name = "End date")]
- [DataType(DataType.Date)]
- [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
- public DateTime EndDate { get; set; }
-
- [Required]
- [Display(Name = "Order number")]
- public int OrderNumber { get; set; }
- [Required]
- [Display(Name = "Is dirty")]
- public bool IsDirty { get; set; }
- [Required, StringLength(15)]
- [Display(Name = "Data Server IP")]
- [RegularExpression(@"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)
- {3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$",
- ErrorMessage = "Data Server IP should be in the form of 255.255.255")]
- public string IP { get; set; }
-
- [Required]
- [Display(Name = "Record data type")]
- [RegularExpression(@"^([1-2])$",
- ErrorMessage = "Record Data Type should be 1 or 2")]
- public int Type { get; set; }
-
- [Display(Name = "Record identifier")]
- [RegularExpression(@"^([0-9])$",
- ErrorMessage = "Record identifier should be between 0 to 9")]
- public int RecordIdentifier { get; set; }
- }
Describing Model Class
Here are some points we should notice in our model class:
1. Initial Date and End Date should be of Date type and formatted as MM/dd/yyyy:
- [DataType(DataType.Date)]
- [DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
- public DateTime InitialDate { get; set; }
2. Here, we are using Data annotations.
3. We set ApplyFormatInEditMode = true so that while in mode, the user shouldn't forget to supply the required format.
4. Our date fields should contain a Calendar control on the browsers that obeys HTML5 rules.
5. IP should be formatted in the actual IP format (to avoid entering unwanted strings).
- [Display(Name = "Data Server IP")]
- [RegularExpression(@"^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.)
- {3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$",
- ErrorMessage = "Data Server IP should be in the form of 255.255.255")]
- public string IP { get; set; }
6. Here, we used RegularExpression, the app will throw an error if it doesn't match.
7. The record data type should be 1 or 2.
- [Required]
- [Display(Name = "Record data type")]
- [RegularExpression(@"^([1-2])$", ErrorMessage = "Record Data Type should be 1 or 2")]
- public int Type { get; set; }
8. If the expression does not match, it will throw an error message.
9. Record identifier should be in the range 0-9.
10. If the expression does not match, it will throw an error message as in the following:
Why All Checks Are On the Client Side?
In this article, we are implementing the ASP.NET WEB API in our client project that is in ASP.NET MVC4. Here we want to ensure that each and every request should be verified and error-free. There are many debates on this approach, whether to implement it client-side or at services-side. In my view, services is the centralized process and it would be calling from multiple clients, so, it's the responsibility of each and every client of an incoming request to be verified and error-free (here incoming request does not contain any security logic, here I meant to say only about normal validation data checks).
Create Controller
1. Under Solution Explorer, right-click on the Controllers folder and click Controller.
2. From the Add controller dialog, enter the Controller name ServerDataController and select MVC controller with empty read/write actions from the Template dropdown, click on "Add".
Describing Controller
Our ServerDataController will consume an ASP.NET WEB API using RestSharp (we'll use our helper class, created above).
- static readonly IServerDataRestClient RestClient = new ServerDataRestClient();
-
- Above, we simply initialized our ServerDataRestClient
- private IServerDataRestClient _restClient;
-
- public ServerDataController(IServerDataRestClient restClient)
- {
- _restClient = restClient;
- }
The preceding is another flavor where we need to use Inversion Of Control (IOC).
- public ActionResult Index()
- {
- return View(RestClient.GetAll());
- }
In the preceding, our Index ActionResult method will get all ServerData records from services and render our view. We need to add views at this point.
Create View
At this point, we need a UI to show output or provide an interface to our user to interact with the application. So, we need to add a view.
The direct/rough way to add a view is, from Solution Explorer, add a new folder ServerData and right-click on it, then click on Add View.
From the Add View dialog, name your view like Index. Select Razor as the ViewEngine, create a strongly typed view and select ServerDataModel as a Model class. I use a Scaffold Template of List (you can ignore that if do not want to use it), use your master layout and click on "Add".
It will add a new view to the project.
- @model IEnumerable<consumewebapi.models.serverdatamodel>
-
- @{ ViewBag.Title = "Manipulate Server Data";
- Layout = "~/Views/Shared/_Layout.cshtml";
- }</consumewebapi.models.serverdatamodel>
We did a little bit of manipulation to get the output:
- @string.Format(item.IsDirty ? "Yes" : "No")
It will give us Yes or No showing whether or not our Record is dirty.
The following same procedure is to add other views, here is the structure:
Executing the Project
Finally, we are done with all of our customizations and changes. It's now time to run our project. Just click run or hit F5. Our Index page will be rendered as:
Closing Notes
- Ah! ASP.NET MVC4 does not provide direct implementation to use RestSharp. There is a good way to add RestSharp supports to our project and then we can use this awesome framework.
- I have created a demo app here, you can use this and adapt the code in part or as a whole. I will be glad to hear from you if you find any issues or other things you need to handle.