In order for an app to communicate with an API via HTTP, it needs an HTTP library. Because we are using .NET and C# to build a Xamarin.Forms app, we can leverage a library within the .NET Framework called System.Net.Http.HttpClient
. The .NET HttpClient
provides a mechanism to send and receive data via standard HTTP methods such as GET
and POST
.
Continuing to keep separation and abstraction key to our app architecture, we will want to keep the specific logic related to the HttpClient
separated from the rest of the app. In order to do this, we will write a base service class in our core library that will be responsible for handling HTTP communications in a generic way. This provides a building block for any domain-specific data services we might need to write, for example, a service that is responsible for working with log entries in the API. Any class that will inherit from this class will be able to send HTTP request messages using standard HTTP methods (such as GET
, POST
, PATCH
, DELETE
) and get back HTTP response messages without having to deal with HttpClient
directly.
As we saw in the preceding section, we are able to post data to the API in the form of JSON; and when we receive data from the API, it's also returned in JSON format. In order for our app to translate its C# models into JSON for use in a HTTP request body, the model will need to be serialized. In contrast, when an HTTP response message is received in JSON, it needs to be deserialized into the appropriate C# model. The most widely used method to do this in .NET software is to use a library called Json.NET.
In order to create a base HTTP service, perform the following steps:
HttpClient
NuGet package to the core library project.Json.NET
NuGet package to the core library project and each of the platform-specific projects.Services
folder of the core library named BaseHttpService
:public abstract class BaseHttpService { }
async
method to the BaseHttpService
class named SendRequestAsync<T>
that takes in a Uri
named url
, a HttpMethod
named httpMethod
, a IDictionary<string,string>
named headers
, and an object
named requestData
. These four parameters will be used to construct an HTTP request. The url
parameter is the full URL of the API endpoint for the request. The httpMethod
optional parameter is used to make the request a GET
, POST
, and so on. The headers
optional dictionary parameter is a collection of string
key/value pairs used to define the header(s) of the request (such as authentication.) Finally, the requestData
optional parameter is used to pass in an object that will be serialized into JSON and included in the body of POST
requests:protected async Task<T> SendRequestAsync<T>( Uri url, HttpMethod httpMethod = null, IDictionary<string, string> headers = null, object requestData = null) { var result = default(T); // Default to GET var method = httpMethod ?? HttpMethod.Get; // Serialize request data var data = requestData == null ? null : JsonConvert.SerializeObject (requestData); using (var request = new HttpRequestMessage (method, url)) { // Add request data to request if (data != null) request.Content = new StringContent ( data, Encoding.UTF8, "application/json"); // Add headers to request if (headers != null) foreach (var h in headers) request.Headers.Add (h.Key, h.Value); // Get response using (var handler = new HttpClientHandler ()) { using (var client = new HttpClient (handler)) { using (var response = await client.SendAsync (request, HttpCompletionOption.ResponseContentRead)) { var content = response.Content == null ? null : await response .Content .ReadAsStringAsync (); if (response.IsSuccessStatusCode) result = JsonConvert .DeserializeObject<T> (content); } } } } return result; }
Now that we have a base HTTP service, we can subclass it with classes that are more specific to our data model, which we will do in the next section.
18.219.239.118