In today’s article, we will see how to consume Web APIs in ASP.NET Core MVC application using Factory Pattern and HttpClient Request.
Why do we need this?
In modern application architecture (Service Oriented or Microservices), we need to make HttpClient calls to get and post the data to/from a server. In our application, we don’t connect to the database. We will have APIs that will connect to the database according to our request; so in order to achieve that, we should know how to consume Web APIs.
So now, let’s get started.
In our application, the APIs that we will use are created in my previous article. We will consume those APIs. Let’s create our project. We will create a MVC application in ASP.NET Core 2.0.
Once our project is created, we will create another project with the same solution. That project will contain models that will be used in APIs.
Now, to create models in this project, we will need the request and response of the Web API that we are about to consume (When you consume any API, you should have its request and response).
So, the GetAllUsers API returns the list of users with certain properties and since this method is get, so there is no request in the body.
Now, according to this, we will create our UsersModel.
I have decorated this class with DataContract attribute in order to make it serialized and decorated each property inside it with DataMember and given it’s Name property the same as in the response JSON.
This Name property will be helpful in a way such that when you decide to rename your fields then your contract to Web API will not break.
Now we see the response of SaveUsers,
As we can see input is the user model and output is another model (Since we created API we know the structure of model so I will create another model class Message.cs , I will show you another way to get class from JSON)
Now we will create another project inside our solution CoreApiClient. This project will be responsible for communicating with our API.
Now in this project we will create a partial class with some internal methods that will help us in consuming web API
Constructor of class
- private readonly HttpClient _httpClient;
- private Uri BaseEndpoint { get; set; }
-
- public ApiClient(Uri baseEndpoint)
- {
- if (baseEndpoint == null)
- {
- throw new ArgumentNullException("baseEndpoint");
- }
- BaseEndpoint = baseEndpoint;
- _httpClient = new HttpClient();
- }
As you can see we have two private fields of type HttpClient and Uri. In constructor of this class we will pass the baseEndPoint of our API and then we will initialize our HttpClient object
Our next method is a common method to make get calls
- private async Task<T> GetAsync<T>(Uri requestUrl)
- {
-
- var response = await _httpClient.GetAsync(requestUrl, HttpCompletionOption.ResponseHeadersRead);
- response.EnsureSuccessStatusCode();
- var data = await response.Content.ReadAsStringAsync();
- return JsonConvert.DeserializeObject<T>(data);
- }
As you can see this method will take requestUrl as input and then will make a http call to that URL and then we will have the response as string which then we will deserialize using JsonConvert which will be found in Newtonsoft.Json namespace.
Next will be a property for date types
- private static JsonSerializerSettings MicrosoftDateFormatSettings
- {
- get
- {
- return new JsonSerializerSettings
- {
- DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
- };
- }
- }
This property will be used so that our dates our properly formatted when we send it through the server (Although we don’t need it in this example but I thought it will be nice to tell you about it).
Our next method will be to create content for post request from our models
- private HttpContent CreateHttpContent<T>(T content)
- {
- var json = JsonConvert.SerializeObject(content, MicrosoftDateFormatSettings);
- return new StringContent(json, Encoding.UTF8, "application/json");
- }
This is a very simple method which will serialize our model object before sending it to the request
Our next method(s) will be common methods to make post calls
- private async Task<Message<T>> PostAsync<T>(Uri requestUrl, T content)
- {
-
- var response = await _httpClient.PostAsync(requestUrl.ToString(), CreateHttpContent<T>(content));
- response.EnsureSuccessStatusCode();
- var data = await response.Content.ReadAsStringAsync();
- return JsonConvert.DeserializeObject<Message<T>>(data);
- }
-
-
- private async Task<Message<T1>> PostAsync<T1, T2>(Uri requestUrl, T2 content)
- {
-
- var response = await _httpClient.PostAsync(requestUrl.ToString(), CreateHttpContent<T2>(content));
- response.EnsureSuccessStatusCode();
- var data = await response.Content.ReadAsStringAsync();
- return JsonConvert.DeserializeObject<Message<T1>>(data);
- }
These methods will help us make post calls to the server. There are two types of methods both return Message<T> (here message is our model class), first one takes input model and returns the same type of model inside Message and the other one takes different input and returns different Output model in Message<T>. I have added message here because this is the pattern of my web APIs.
You can simply remove Message and make its return Type T just like in GetAsync method.
There is one more method in this class.
- private Uri CreateRequestUri(string relativePath, string queryString = "")
- {
- var endpoint = new Uri(BaseEndpoint, relativePath);
- var uriBuilder = new UriBuilder(endpoint);
- uriBuilder.Query = queryString;
- return uriBuilder.Uri;
- }
This method will take a string url and query string and will return a Uri type which will be passed in get and post common methods.
Here is the entire class
- public partial class ApiClient
- {
-
- private readonly HttpClient _httpClient;
- private Uri BaseEndpoint { get; set; }
-
- public ApiClient(Uri baseEndpoint)
- {
- if (baseEndpoint == null)
- {
- throw new ArgumentNullException("baseEndpoint");
- }
- BaseEndpoint = baseEndpoint;
- _httpClient = new HttpClient();
- }
-
-
-
-
- private async Task<T> GetAsync<T>(Uri requestUrl)
- {
- addHeaders();
- var response = await _httpClient.GetAsync(requestUrl, HttpCompletionOption.ResponseHeadersRead);
- response.EnsureSuccessStatusCode();
- var data = await response.Content.ReadAsStringAsync();
- return JsonConvert.DeserializeObject<T>(data);
- }
-
-
-
-
- private async Task<Message<T>> PostAsync<T>(Uri requestUrl, T content)
- {
- addHeaders();
- var response = await _httpClient.PostAsync(requestUrl.ToString(), CreateHttpContent<T>(content));
- response.EnsureSuccessStatusCode();
- var data = await response.Content.ReadAsStringAsync();
- return JsonConvert.DeserializeObject<Message<T>>(data);
- }
- private async Task<Message<T1>> PostAsync<T1, T2>(Uri requestUrl, T2 content)
- {
- addHeaders();
- var response = await _httpClient.PostAsync(requestUrl.ToString(), CreateHttpContent<T2>(content));
- response.EnsureSuccessStatusCode();
- var data = await response.Content.ReadAsStringAsync();
- return JsonConvert.DeserializeObject<Message<T1>>(data);
- }
-
- private Uri CreateRequestUri(string relativePath, string queryString = "")
- {
- var endpoint = new Uri(BaseEndpoint, relativePath);
- var uriBuilder = new UriBuilder(endpoint);
- uriBuilder.Query = queryString;
- return uriBuilder.Uri;
- }
-
- private HttpContent CreateHttpContent<T>(T content)
- {
- var json = JsonConvert.SerializeObject(content, MicrosoftDateFormatSettings);
- return new StringContent(json, Encoding.UTF8, "application/json");
- }
-
- private static JsonSerializerSettings MicrosoftDateFormatSettings
- {
- get
- {
- return new JsonSerializerSettings
- {
- DateFormatHandling = DateFormatHandling.MicrosoftDateFormat
- };
- }
- }
-
- private void addHeaders()
- {
- _httpClient.DefaultRequestHeaders.Remove("userIP");
- _httpClient.DefaultRequestHeaders.Add("userIP", "192.168.1.1");
- }
- }
Here I have added another method addHeaders and called it in get and post common methods. This is just to demonstrate how you can send your custom headers in requests.
As you have noticed this is a partial class. You may wonder why we have create this as a partial class.
It's because now we will create a UserClient class in this project which will be partial of this so that it can access its methods. Here is the UserClient class with two methods to call list of users and save user.
Here is the entire UserClient class
- public partial class ApiClient
- {
- public async Task<List<UsersModel>> GetUsers()
- {
- var requestUrl = CreateRequestUri(string.Format(System.Globalization.CultureInfo.InvariantCulture,
- "User/GetAllUsers"));
- return await GetAsync<List<UsersModel>>(requestUrl);
- }
-
- public async Task<Message<UsersModel>> SaveUser(UsersModel model)
- {
- var requestUrl = CreateRequestUri(string.Format(System.Globalization.CultureInfo.InvariantCulture,
- "User/SaveUser"));
- return await PostAsync<UsersModel>(requestUrl, model);
- }
- }
Now our work in model and apiClient project is done. We just have to call this api client through our web.
For this we will use lazy loading and factory pattern (Singleton class)
Now in our web project we will add a folder called utility and in the we will add a class ApplicationSettings.cs
Now in our home controller we will add this below code.
This class will hold our base web API URL.
Now we will add our basi API Url in appsettings.json
- "MySettings": {
-
- "WebApiBaseUrl": "http://localhost:6846/api/"
-
- }
After modifying out appsettings file, we will read it in our controller and set it into ApplicationSettings.cs
The part in yellow is how to read values from appsettings.json.Clik Here to know more.
The part in red is how to get value and set it in ApplicationSettings.
Now we will create a Factory folder and inside it we will create a factory class.
As you can see it is a singleton class and it used lazy loading to initialize our ApiClient. In the static constructor of our class we will get the value from ApplicationSettings file and set it in the apiUri field in the class.
Now how to use this class?
This is the method to use this class. Since our methods in api client were async Task so we need to await this. We can see our method GetUsers also in the suggestion (Note :- we will also see all our methods in this suggestion box)
This is how we will call it.
Now our API is called so let’s run it and see the result.
As you can see we get list of 5 users and this is the expanded view of first model.
So we have done a get request successfully. Now we will do the post request.
According to our save request here is our controller (with some hard coded values, you can get them from your view).
Now let’s run it,
Congratulations! You have successfully consumed web APIs in your ASP.NET Core 2.0 MVC application.
If you wish to see/download the code please Click Here!
Summary
In this article we have seen how to consume web APIs in ASP.NET core MVC application using factory pattern and lazy loading. We have used partial classes and HttpClient to make web requests.
Hope you all liked it.
Happy coding!