Share via


ASP.NET: How to consume WEB API from MVC4 using RestSharp

 


Abstract

Through-out this 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 of scenarios, we develop an application of ASP.NET MVC4 using ASP.NET WEB API. But as a RESTFul service like the ASP.NET WEB API, we meant to use by different clients. In this article we will see how to consume 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 to read my previous article, where I defined how to create the ASP.NET WEB API (Crud Operations using Fluent NHibernate).


Pre-requisite

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?

As we are going to use RestSharp to call our ASP.NET WEB API URIs, so, first of  all lets discuss "RestSharp". This is nothing but a Simple REST and HTTP API  Client for .NET. It provides us to a simple way by which we can just initialize a RestClient, pass a Request, define a Method (GET, POST, PUT, DELETE) and get a response.

 Followings are commonly used snippet:

//Create a restclient

RestClient restClient = RestClient("url");

//Create request with GET

var request = new RestRequest("api/serverdata", Method.GET);

  • Do not forget to provide RequestFormat and RestSharp automatically serialize/deserialize complex objects like Models like ServerDataModel in our demo project.

//Do not forget while using complex types

var request = new RestRequest("api/serverdata", Method.GET)

* {RequestFormat = DataFormat.Json};*

  • Get 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 are we going to consume?

As mentioned earlier that in this article we will consume an existing ASP.NET WEB API URIs (hosted on server), below is the table mentioning all URIs:

Action

HTTP Method

Relative URI

Get a list of serverdata

GET

/api/serverdata

Get a serverdata by ID

GET

/api/serverdata/id

Get serverdata by datatype

GET

/api/serverdata/type/datatype

Get serverdata by machine IP

GET

/api/serverdata/ip/ip

Create a fresh serverdata

POST

/api/serverdata

Update an existing serverdata

PUT

/api/serverdata/id

Delete an existing serverdata

DELETE

/api/serverdata/id

Refer to the demo app: Demo ASP.NET WEB API.

 


Create the Web Project

Let's start creation of our new ASP.NET project (client project) by following the below mentioned step(s):

  • 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 as consumewebapi, you can choose whatever you want J

From Project Template, select Internet Application and Razor from View Engine dropdown list and click 'ok'.

You can also check Create unit test project checkbox, if are doing Test driven development and I highly recommend the same. In this article, we are not covering this part.

Now, after the above step(s), we have default ASP.NET MVC4 project template with us, later on we will add our stuff.

 


Add RestSharp Support to Project

We are going to use RestSharp to consume our ASP.NET WEB API, follow these steps:

Goto Tools->NuGet Package Manager->Package Manager Console.

From Package Manager Console, run the following command:

Install-Package RestSharp

 


Add Rest Client

  1. From Solution Explorer, create a new folder and named it Helper - this folder will contain all our helper classes required for RestSharp client (these classes will play an interface between our client and services).
  2. Add an interface and name it IServerDataRestClient.

Complete code of IServerDataRestClient looks like:

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);
} 
  1. Add new class under Helper folder and named it as ServerDataRestClient and implement interface IServerDataRestClient:
public class ServerDataRestClient : IServerDataRestClient

{

 //implementation

}

We need to create a RestClient, create a variable private readonly RestClient _client; in the class and initialize the same in the constructor.

//initializing RestClient

public ServerDataRestClient()

{

 _client = new RestClient(_url);

}

In the above, while we are initializing RestClient object, we are providing BaseUrl nothing just a complete name of url like http://gaurav-arora.com

We can also do this:

_client = new RestClient {BaseUrl = _url};

We are fetching base URL from our config files, why it is in config files. It is recommended for large projects where we have different environments like Dev, Staging,QA, Prod etc.

//getting base url from config

private readonly string _url = ConfigurationManager.AppSettings["webapibaseurl"];

Now, we required a request it is nothing but contains 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 while you are working with complex classes, like here we are using ServerDataModel class.

In DEBUG mode, check _client in Quick watch (Ctrl + D,Q), you will find all the things we set while creating our RestClient object.

Our client is ready to convey our request and get the response.

var response = _client.Execute<List<ServerDataModel>>(request);

The above will give us the output in a list of our ServerDataModel class.

Open Quick watch for response, you will get 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.

First node contains our actual content in JSON format with other information, e.g., ContentLength, ContentType, Cookies, ErrorMessage, Header, Request, ResponseStatus, StatusCode, etc.

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 for 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);

Below will give us output of type ServerDataModel:

var response = _client.Execute<serverdatamodel>(request);

Here, 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 Models folder and Add -> New Item (or hit Ctrl + Shift + A). Choose 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; }
  1. Here, we are using Data annotations.
  2. We set ApplyFormatInEditMode = true so, during edit mode, user shouldn't forget to supply the required format.
  3. Our date fields should contain calendar control on the browsers which obeys HTML5 rules.

  1. 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; }

  1. Here, we used RegularExpression, the app will throw an error if it doesn't match.

  1. 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; }
  1. If expression does not match, it will throw an error message.

  1. Record identifier should be between 0-9.
  2. If expression does not match, it will throw an error message

 


Why All Checks Are At Client Side?

In this article, we are implementing ASP.NET WEB API in our client project which is in ASP.NET MVC4, here we want to make sure that each and every request should be verified and error-free. Three are lot of debates on this approach whether we implement are 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 that incoming request should 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 Controllers folder and click Controller.

  1. From Add controller dialog, enter Controller name ServerDataController and select MVC controller with empty read/write actions from Template dropdown, click on 'Add'.

 


Describing Controller

Our ServerDataController is going to consume 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;

}

Above is another flavor, where we need to use inversion of control (IOC).

public ActionResult Index()

{

   return View(RestClient.GetAll());

}

In the above, 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, where we can 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, from Solution Explorer, add a new folder ServerData and right click on it, then click on Add View.

From Add View dialog, name your view like Index, select Razor as ViewEngine, create strongly typed view and select ServerDataModel as a Model class, I use Scaffold Template of List (you can ignore if do not want to use), use your master layout and click on 'Add'.

It will add a new view to 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 our Record is dirty or not.

Following same step(s) add other views, here is the structure:

 


Executing the Project

Finally, we are done with all of our customizations, changes, now it's time to run our project. Just click run or hit F5. Our Index page will be rendered as:

 


Closing Notes

  • Ah! ASP.NET MVC4 is not providing 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 as a part or whole. I will be glad to hear from you, if you find any issues or other things you need to handle.

Download


See Also