Demolite.Http 0.2.1

dotnet add package Demolite.Http --version 0.2.1
                    
NuGet\Install-Package Demolite.Http -Version 0.2.1
                    
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="Demolite.Http" Version="0.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Demolite.Http" Version="0.2.1" />
                    
Directory.Packages.props
<PackageReference Include="Demolite.Http" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Demolite.Http --version 0.2.1
                    
#r "nuget: Demolite.Http, 0.2.1"
                    
#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.
#:package Demolite.Http@0.2.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Demolite.Http&version=0.2.1
                    
Install as a Cake Addin
#tool nuget:?package=Demolite.Http&version=0.2.1
                    
Install as a Cake Tool

Demolite.Http

A base class for typed api clients on top of HttpClient.

  • Every call returns a Result or Result<T> from Demolite.Core. Http failures are returned, not thrown.
  • Authentication is a separate, reusable handler.
  • Works with IHttpClientFactory and dependency injection.

Migrating from 0.1.x

Version 0.2.0 is a rewrite and breaks the old API.

Before Now
AbstractHttpRepository ApiClient
IHttpResponse Result and Result<T>
AbstractSerializer Built in. Pass JsonSerializerOptions to the client.
Set*Headers, PrepareRequestAsync AuthHandler with an IAuthProvider, or CreateRequest for single calls
Log event ILogger
Demolite.Http.Uri namespace Demolite.Http.Requests
.NET 9 .NET 10

Demolite.Http.Legacy is removed.

Writing a client

Inherit from ApiClient and expose your calls. The verb methods are protected, so callers only see your methods.

public sealed class ArmorClient(HttpClient httpClient, JsonSerializerOptions? options = null, ILogger<ArmorClient>? logger = null)
    : ApiClient(httpClient, options, logger)
{
    public Task<Result<Armor>> GetAsync(int id, CancellationToken ct = default)
        => GetAsync<Armor>($"armors/{id}", ct);

    public Task<Result<Armor>> CreateAsync(Armor armor, CancellationToken ct = default)
        => PostAsync<Armor>("armors", armor, ct);

    public Task<Result> DeleteAsync(int id, CancellationToken ct = default)
        => DeleteAsync($"armors/{id}", ct);
}
  • Methods with a type parameter deserialize the response body. Methods without one ignore it.
  • Request bodies are sent as json.
  • An empty response body, such as a 204, gives a successful result with a default value.
  • Without options, the web defaults are used (camel case, case insensitive).
  • Without a logger, nothing is logged.

Errors

Code Meaning
Http.<status> The api returned a failure status. The message is the response body.
Http.RequestFailed The request could not be sent, for example the host is unreachable.
Http.Timeout The request timed out.
Http.DeserializationFailed The body is not valid for the requested type. The raw content is in the metadata.
Http.EmptyBody The body is valid json that is null.

A cancelled token throws OperationCanceledException, as usual.

Headers for a single call

var request = CreateRequest(HttpMethod.Get, "armors");
request.Headers.Add("X-Type", type);

return SendAsync<List<Armor>>(request, ct);

Set headers that never change once in the AddApiClient setup. Do not change DefaultRequestHeaders per call, because the client is shared between threads.

Registration

services.AddApiClient<ArmorClient>("https://armors.example/api/")
    .AddStaticAuth("Token", sp => sp.GetRequiredService<ArmorSettings>().ApiKey);

AddApiClient returns the normal IHttpClientBuilder, so everything from Microsoft.Extensions.Http works. The base address can also be resolved from the services.

services.AddApiClient<ArmorClient>(sp => sp.GetRequiredService<ArmorSettings>().BaseUrl);

For retries and timeouts, use the Microsoft resilience handler.

services.AddApiClient<ArmorClient>("https://armors.example/api/")
    .AddStandardResilienceHandler();

Logging with Serilog

The package only uses Microsoft.Extensions.Logging. If your host uses Serilog (UseSerilog()), the messages of the clients go through Serilog.

Authentication

AuthHandler sets the Authorization header on every request. It asks an IAuthProvider for the header. If the provider fails, the request is not sent and the client returns Http.401 with the failure message.

Registration Use for
AddStaticAuth(scheme, token) Api keys and tokens. The token is read on every request, so rotating credentials work.
AddBasicAuth(userName, password) Basic authentication.
AddHeader(name, value) Any other header, such as an api key header. The value is read on every request.
AddAuth<TProvider>() Your own provider, registered as a singleton.
AddAuth(factory) Your own provider, created by a factory.

Tokens that expire

Inherit from CachedTokenProvider and implement one method. The base class caches the token, renews it 60 seconds before it expires, and makes concurrent requests share one token request.

public sealed class ArmorTokenProvider(ArmorAuthClient authClient, ArmorSettings settings) : CachedTokenProvider
{
    protected override async Task<Result<AccessToken>> RequestTokenAsync(CancellationToken ct)
    {
        var result = await authClient.AuthenticateAsync(settings.Key, settings.Secret, ct);

        return result.IsSuccess
            ? Result<AccessToken>.Success(new AccessToken(result.Value!.Token, TimeSpan.FromSeconds(result.Value.ExpiresIn)))
            : Result<AccessToken>.Failure(result.Error!);
    }
}

services.AddApiClient<ArmorClient>("https://armors.example/api/").AddAuth<ArmorTokenProvider>();

Call Invalidate() on the provider to force a new token on the next request.

Building uris

RequestUri builds uris with encoded segments and parameters. Build() returns the string.

var uri = new RequestUri("armors")
    .WithSegments("type", "leather")
    .WithParameter("page", 2)
    .Build();

await client.GetAsync<List<Armor>>(uri, ct);
  • Segments and parameter names and values are url-encoded.
  • Numbers are formatted with the invariant culture.
  • A parameter with a null value is skipped.
  • A parameter name can be added more than once.
Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.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
0.2.1 52 10/11/2026
0.2.0 54 10/11/2026
0.1.1 638 8/29/2025
0.0.1 361 10/6/2024