Generic Class makes .NET Core HttpClient Calls (New!)

Note: This is an enhancement of the static HTTPClientHelper class introduced here.

Here’s a new and improved class that abstracts HttpClient calls. You add the class to your dependency injection container and then just inject it normally in classes that need it. The class is generic, so any type can be used.

Adding IHttpClientHelper to the DI container is a little tricky because the constructor not only expects IHttpClientFactory to be pulled from the DI container, but also the name of the factory connection, ProjectsAPI, in the example below.

// HttpClientFactory
services.AddHttpClient("ProjectsAPI", client =>
{
    client.BaseAddress = new Uri(Configuration["ProjectsAPIServer"]);
    client.DefaultRequestHeaders.Add("APIKey", Configuration["APIKey"]);
    client.DefaultRequestHeaders.Add("X-Version", Configuration["X-VERSION"]);
});

// HttpClientFactory will take care of connection caching, ProjectsAPI is the name 
// of the factory, just above.
services.AddSingleton<IHTTPClientHelper, HTTPClientHelper>(s =>
             new HTTPClientHelper(s.GetService<IHttpClientFactory>(), "ProjectsAPI")
             );

Note: APIKey is just a simple secret string used to authenticate users of the API. X-Version is the API version being requested.

To use the class, inject it into your class normally.

public class ProjectRepository : IProjectRepository
{
    private readonly IHTTPClientHelper httpClientHelper;
    public ProjectRepository(IHTTPClientHelper httpClientHelper)
    {
        this.httpClientHelper = httpClientHelper;
    }
...

Then just use it. Note that Project below can be any type you expect returned. It might be IEnumerable<Project> if you expect a list of projects returned. This is possible because the class is generic.

public async Task<Project> GetProjectAsync(int id)
{
    Project project = null;
    string url = $"api/projects/" + id.ToString();
    project = await httpClientHelper.GetAsync<Project>(url);
    return project;
}

Here’s the entire HTTPClientHelper class. If you want to use the IHTTPClientHelper interface to abstract the injection, just use Visual Studio to extract it.

using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace ITProjects.Models
{
    // HTTPClientHelper class
    //
    // Extract the interface and inject it into startup.cs: 
    //
    // services.AddSingleton<IHTTPClientHelper, HTTPClientHelper>();
    //
    // Because this class is dependent on HttpClientFactory, you also have to include 
    // it in the DI container: 
    //
    // services.AddHttpClient("ProjectsAPI", client =>
    //        {
    //            client.BaseAddress = new Uri(Configuration["ProjectsAPIServer"]);
    //            client.DefaultRequestHeaders.Add("APIKey", Configuration["APIKey"]);
    //            client.DefaultRequestHeaders.Add("X-Version", Configuration["X-VERSION"]);
    //        });
    //
    // APIKey is a secret key we send to authenticate ourselves, perhaps a GUID. 
    // X-Version contains the version of the API we want to access, i.e., 1.0 
    // BaseAddress is the URL of the server, i.e., https://localhost:5001
    //
    public class HTTPClientHelper : IHTTPClientHelper
    {
        IHttpClientFactory httpClientFactory;
        HttpClient client;
        String ClientName;

        public HTTPClientHelper(IHttpClientFactory httpClientFactory, string ClientName)
        {
            this.httpClientFactory = httpClientFactory;
            this.ClientName = ClientName;
        }

        #region Generic, Async, static HTTP functions for GET, POST, PUT, and DELETE             

        public async Task<T> GetAsync<T>(string url)
        {
            T data;
            client = httpClientFactory.CreateClient(ClientName);
            try
            {
                using (HttpResponseMessage response = await client.GetAsync(url))
                using (HttpContent content = response.Content)
                {
                    string d = await content.ReadAsStringAsync();
                    if (d != null)
                    {
                        data = JsonConvert.DeserializeObject<T>(d);
                        return (T)data;
                    }
                }
            }
            catch (Exception ex)
            {
                throw;
            }
            Object o = new Object();
            return (T)o;
        }

        public async Task<T> PostAsync<T>(string url, HttpContent contentPost)
        {
            T data;
            client = httpClientFactory.CreateClient(ClientName);
            using (HttpResponseMessage response = await client.PostAsync(url, contentPost))
            using (HttpContent content = response.Content)
            {
                string d = await content.ReadAsStringAsync();
                if (d != null)
                {
                    data = JsonConvert.DeserializeObject<T>(d);
                    return (T)data;
                }
            }
            Object o = new Object();
            return (T)o;
        }

        public async Task<T> PutAsync<T>(string url, HttpContent contentPut)
        {
            T data;
            client = httpClientFactory.CreateClient(ClientName);

            using (HttpResponseMessage response = await client.PutAsync(url, contentPut))
            using (HttpContent content = response.Content)
            {
                string d = await content.ReadAsStringAsync();
                if (d != null)
                {
                    data = JsonConvert.DeserializeObject<T>(d);
                    return (T)data;
                }
            }
            Object o = new Object();
            return (T)o;
        }

        public async Task<T> DeleteAsync<T>(string url)
        {
            T newT;
            client = httpClientFactory.CreateClient(ClientName);

            using (HttpResponseMessage response = await client.DeleteAsync(url))
            using (HttpContent content = response.Content)
            {
                string data = await content.ReadAsStringAsync();
                if (data != null)
                {
                    newT = JsonConvert.DeserializeObject<T>(data);
                    return newT;
                }
            }
            Object o = new Object();
            return (T)o;
        }
        #endregion
    }
}

You may also like...