Byteology.TypedHttpClients 1.0.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Byteology.TypedHttpClients --version 1.0.0                
NuGet\Install-Package Byteology.TypedHttpClients -Version 1.0.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Byteology.TypedHttpClients" Version="1.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Byteology.TypedHttpClients --version 1.0.0                
#r "nuget: Byteology.TypedHttpClients, 1.0.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Byteology.TypedHttpClients as a Cake Addin
#addin nuget:?package=Byteology.TypedHttpClients&version=1.0.0

// Install Byteology.TypedHttpClients as a Cake Tool
#tool nuget:?package=Byteology.TypedHttpClients&version=1.0.0                

Nuget Code Coverage

Security Rating Reliability Rating Maintainability Rating

Byteology's Typed HTTP Clients

Usually when consuming an HTTP service, you will want to use a typed HTTP client. There are two approaches on how to write them:

You can generate it using an existing OpenAPI documentation and your favorite tool that generates the actual code. Unfortunately, not all services provide an OpenAPI documentation and even if they did, the generated code is not always exactly what you need. Maybe there are arrays in the query string that need to be parsed differently or maybe there is some other inconstancy that forces you to make changes to the generated code and persist them after regeneration. Additionally, many of the generation tools don’t use any boilerplate code so you’ll have to change every single method call which defeats the purpose of the auto-generation. Another reason to not use auto-generated HTTP clients is that usually they will generate code for the whole service and maybe you want just a tiny part of it. This includes both methods and resources.

Another way that lets you have more control over the client is to just write it manually. The problem with this is that the process is tedious at best and error-prone at least. To avoid this, we've created an extensible typed HTTP client base class that provided a lean contract of the service can execute HTTP requests and process their responses.

Defining the Service Contract

Before being able to consume a service you have to define its contract or at least the parts of it you'll be using. The contract is an interface with async methods that are decorated with the HttpEndpointAttribute. The typed HTTP client will create an implementation of the contract on its initialization during runtime. The implementation details will be inferred from the methods' signatures and their attributes. Below is an example of a service contract. You have to manually create the interface but the resources' types can be either manually created or auto-generated by a tool when applicable.

public class Book
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Author { get; set; }
    public DateTime PublicationDate { get; set; }
}
public interface ILibraryService
{
    [HttpEndpoint("GET", "/books/{id}")]
    Task<Book> GetBookAsync(string id);
  
    [HttpEndpoint("GET", "/books")]
    Task<IEnumerable<Book>> GetBooksByAuthorAsync(string author);
  
    [HttpEndpoint("POST", "/books")]
    Task<Book> AddBookAsync([HttpBody] Book book);
  
    [HttpEndpoint("DELETE", "/books/{id}")]
    Task DeleteBookAsync(string id);
}

Consuming the Service

You can access an instance of the service contract in two different ways:

Registering the service contract to the IServiceCollection comes with the benefit of leveraging the IHttpClientFactory. For more info on why you should use it, check out this article.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(ILibraryService services)
    {
        services.AddTypedHttpClient<ILibraryService, JsonHttpClient<ILibraryService>>(client =>
        {
            client.BaseAddress = new Uri("https://mylibraryservice.com");
        });
        
        // Remaining code deleted for brevity.

After that you'll be able to inject ILibraryService into your code and it will send HTTP requests to https://mylibraryservice.com and parse the responses properly. You can also use the parameter of the AddTypedHttpClient method to configure the underlying HttpClient according to your needs.

public class InjectedClass
{
    private readonly ILibraryService _libraryService;

    public InjectedClass(ILibraryService libraryService)
    {
       _libraryService = libraryService;
    }
  
    async void ExampleMethodAsync(string bookId)
    {
        Book book = await _libraryService.Endpoints.GetBookAsync(bookId);
        // ...
    }
}

Directly Initializing a Typed Http Client

You can always just initialize a new typed HTTP client via its constructor and then access its Endpoints property but you have to be careful with the lifecycle of the HttpClient.

async void ExampleMethodAsync(string bookId)
{
    using HttpClient httpClient = new HttpClient()
    {
        BaseAddress = new Uri("https://mylibraryservice.com")
    };
  
    JsonHttpClient<ILibraryService> service = new(httpClient);
  
    Book book = await service.Endpoints.GetBookAsync(bookId);
    // ...
}

Available Clients

Currently the only available client is the JsonHttpClient. It works by serializing and deserializing message contents by using System.Text.Json.JsonSerializer.

Additionally, the TypedHttpClient base class provides useful abstract and virtual methods for implementing your own typed HTTP clients.

Moreover, if you are in need of another commonly used type of client, don't hesitate to create a feature request and we'll be happy to implement it for you.

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.0.0 338 1/12/2023
1.0.0 418 10/20/2021