HTTP Client Service Implementation

The trellispark UX relies on APIs for backend logic processing. To reduce our code base on the UX end, we have implemented a generic HTTP Client service that can be initialized as multiple singletons and used in different ways throughout the application. For detailed documentation about generic classes and their implementation, click here.

The HTTP Client service being a generic reduces the amount of code and classes required. It replaces a series of HTTPClient calls with a single call created multiple times as a singleton. This increases the customizability of the UX application by reducing the complexity of creating a new API. This begins with the class declaration.

public sealed class HTTPClientService<T,U>

T and U are type variables. They allow multiple versions of the same class with non-specific type assignment. They are then individually referenced later in the class. The type variables are assigned to when the class is declared as a singleton in the Program class, and when it is referenced in an Imports.razor.

builder.Services.AddSingleton<HTTPClientService<UserInformation, UserInformation>, HTTPClientService<UserInformation, UserInformation>>();

This line is placed in the Program.cs class inside the Main method. It creates the singleton that will be referenced by the Imports.razor classes.

@inject HTTPClientService<UserInformation, UserInformation> UserClient

This line injects the service in the Imports.razor class. In any blazor project where a class references this service, the Imports.razor will need this injection.

The HTTPClient service depends on an existing HTTPClient object and an existing EventLog object. It’s declaration in the Program.cs of the application must come after declarations of those objects or compilation will fail.

public HTTPClientService(HttpClient httpService, EventLog eventLog)
{
    Http = httpService;
    EventLog = eventLog;
}

Finally, the class includes a single CallAPI task. It takes an input variable of type T and a string that is the URL of the target API, then returns a response variable of type U (remember the class declaration). Because it is a generic class and the variables can’t have specific method calls, the response must first be set as a default instead of a more precise declaration. The initial object is then serialized into json and sent as a post to the given API URL. The response is then deserialized into an object of type U.

public async Task<U> CallAPI(T MyCommand, string myCommandTarget)
{

    U CommandResponse = default;
    try
    {
        HttpContent content = null;
        content = new StringContent(JsonConvert.SerializeObject(MyCommand), Encoding.UTF8, "application/json");
        if (content != null)
        {

             HttpResponseMessage response = await Http.PostAsync(myCommandTarget, content);
             string SQLReponse = await response.Content.ReadAsStringAsync();
             CommandResponse = JsonConvert.DeserializeObject<U>(SQLReponse);
                    
         }
    }
    catch (TaskCanceledException tce) when (tce.InnerException is TimeoutException te)
    {
        await EventLog.Log(1, "HTTPClientService.CallAPI - Client timed out waiting for API response. The command might be still running on server. ", te.ToString());
    }
    catch (Exception e)
    {
        await EventLog.Log(1, "HTTPClientService.CallAPI - Unknown", e.ToString());
    }
    return CommandResponse;
}

The implementation of this service as a generic means that new APIs can be added relatively simply. Code can be wrote into the blazor that relies on a new API, then as long as the input and output types are consistent, singletons can be added for a new HTTPClient service without requiring an additional class. trellispark currently uses this to replace at least 9 different classes with different API calls to different APIs.

Updated on November 30, 2022

Was this article helpful?

Related Articles

Need Support?
Can’t find the answer you’re looking for? Don’t worry we’re here to help!
Contact Support

Leave a Comment