Kanject.Core.Adapter 3.7.4

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Kanject.Core.Adapter --version 3.7.4
                    
NuGet\Install-Package Kanject.Core.Adapter -Version 3.7.4
                    
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="Kanject.Core.Adapter" Version="3.7.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Kanject.Core.Adapter" Version="3.7.4" />
                    
Directory.Packages.props
<PackageReference Include="Kanject.Core.Adapter" />
                    
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 Kanject.Core.Adapter --version 3.7.4
                    
#r "nuget: Kanject.Core.Adapter, 3.7.4"
                    
#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 Kanject.Core.Adapter@3.7.4
                    
#: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=Kanject.Core.Adapter&version=3.7.4
                    
Install as a Cake Addin
#tool nuget:?package=Kanject.Core.Adapter&version=3.7.4
                    
Install as a Cake Tool

Kanject.Core.Adapter

Kanject.Core.Adapter is the outbound HTTP integration layer for Kanject services. It combines typed HttpClient registration, resilient retries, authentication and header helpers, health pings, AOT-safe JSON overloads, and an optional source generator that turns declarative endpoint contracts into production-ready adapter methods.

Use it when an application needs a stable boundary around a payment gateway, shipping carrier, CRM, internal microservice, or any other HTTP API. Application code depends on a typed adapter rather than spreading URLs, credentials, serialization, and status-code handling across controllers and domain services.

Installation

dotnet add package Kanject.Core.Adapter

The package supports .NET 8, .NET 9, and .NET 10. It includes Kanject.Core.Adapter.Annotations transitively for NuGet consumers, so generated adapters normally require no second package reference.

Choose an authoring style

Style Best for What you write
Generated endpoints Most integrations and documentation-first contracts Attributes, request/response DTOs, and partial method signatures
Hand-written adapter Custom protocols, unusual response handling, or incremental migration A subclass plus calls to GetAsync, PostAsync, PutAsync, or DeleteAsync

Both styles use the same AbstractServiceAdapter, HttpClientFactory registration, retry policy, cancellation flow, and response helpers.

Quick start: generated shipping adapter

The following contract uses API-key authentication, a settings-driven base URL, source-generated JSON metadata, route substitution, and an endpoint-specific correlation header.

using System.Text.Json.Serialization;
using Kanject.Core.Adapter;
using Kanject.Core.Adapter.Attributes;
using Kanject.Core.Adapter.Enums;

[AdapterAuth(
    AuthScheme.ApiKey,
    SettingsType = typeof(ParcelApiOptions),
    HeaderMappings = ["X-Api-Key:ApiKey"])]
[AdapterBaseUrl(nameof(ParcelApiOptions.BaseUrl))]
[AdapterDisablePing]
[AdapterJsonSerializerContext(typeof(ParcelAdapterJsonContext))]
public partial class ParcelAdapter(
    HttpClient httpClient,
    ParcelApiOptions settings) : AbstractServiceAdapter(httpClient, shouldDisposeHttpClient: false)
{
    // The generator resolves settings-backed templates from this field.
    private readonly ParcelApiOptions _settings = settings;

    [AdapterEndpoint(HttpVerb.Post, "v1/shipments")]
    [AdapterHeader("Idempotency-Key", "{request.IdempotencyKey}")]
    public virtual partial Task<CreateShipmentResponse?> CreateShipmentAsync(
        CreateShipmentRequest request,
        CancellationToken cancellationToken);

    [AdapterEndpoint(
        HttpVerb.Get,
        "v1/shipments/{ShipmentId}",
        NotFoundReturnsNull = true)]
    public virtual partial Task<ShipmentStatus?> GetShipmentAsync(
        ShipmentLookup request,
        CancellationToken cancellationToken);
}

public sealed class ParcelApiOptions
{
    public required string BaseUrl { get; init; }
    public required string ApiKey { get; init; }
}

public sealed record CreateShipmentRequest(
    string IdempotencyKey,
    string RecipientName,
    string PostalCode,
    decimal WeightKg);

public sealed record CreateShipmentResponse(string ShipmentId, string LabelUrl);
public sealed record ShipmentLookup(string ShipmentId);
public sealed record ShipmentStatus(string ShipmentId, string Status);

[JsonSourceGenerationOptions(PropertyNameCaseInsensitive = true)]
[JsonSerializable(typeof(CreateShipmentRequest))]
[JsonSerializable(typeof(CreateShipmentResponse))]
[JsonSerializable(typeof(ShipmentStatus))]
internal sealed partial class ParcelAdapterJsonContext : JsonSerializerContext;

Register the settings and every generated adapter from the composition root:

using Microsoft.Extensions.DependencyInjection;

builder.Services.AddSingleton(new ParcelApiOptions
{
    BaseUrl = builder.Configuration["ParcelApi:BaseUrl"]
        ?? throw new InvalidOperationException("ParcelApi:BaseUrl is required."),
    ApiKey = builder.Configuration["ParcelApi:ApiKey"]
        ?? throw new InvalidOperationException("ParcelApi:ApiKey is required.")
});

builder.Services.AddGeneratedServiceAdapters(options =>
{
    options.ServiceAdapterMaximumRetryCount = 3;
    options.HandlerLifetime = 5; // minutes
});

Consume it like any typed dependency:

public sealed class ShippingService(ParcelAdapter parcels)
{
    public Task<CreateShipmentResponse?> DispatchAsync(
        CreateShipmentRequest request,
        CancellationToken cancellationToken) =>
        parcels.CreateShipmentAsync(request, cancellationToken);
}

Hand-written adapter

Use the runtime directly when an endpoint requires custom interpretation. Prefer the JsonTypeInfo<T> overloads in trimmed or Native AOT applications.

using Kanject.Core.Adapter;
using Kanject.Core.Adapter.Extensions;

public sealed class FraudAdapter(HttpClient httpClient)
    : AbstractServiceAdapter(httpClient, shouldDisposeHttpClient: false)
{
    public async Task<FraudDecision?> ScoreAsync(
        FraudRequest request,
        CancellationToken cancellationToken)
    {
        using var response = await PostAsync(
            "v2/score",
            request,
            FraudJsonContext.Default.FraudRequest,
            cancellationToken);

        if (response.StatusCode == System.Net.HttpStatusCode.UnprocessableEntity)
        {
            ProblemDetails = await response.ReadProblemDetailsAsync();
            return null;
        }

        response.EnsureSuccessStatusCode();
        return await response.ReceiveJsonAsync(FraudJsonContext.Default.FraudDecision);
    }
}

Runtime reference

Registration and resilience

services.AddServiceAdapter<FraudAdapter>(options =>
{
    options.ServiceAdapterMaximumRetryCount = 3;
    options.HandlerLifetime = 5;
    // options.DisableRetryPolicy = true;
});

AddServiceAdapter<T>() registers a typed client through IHttpClientFactory. Unless disabled, it retries transient HTTP failures and 404 Not Found responses using decorrelated-jitter backoff. The default retry count is 2 and the default handler lifetime is 2 minutes. Only enable retries for operations that are safe to repeat; use idempotency keys for retryable writes.

HTTP operations

Operation Supported payloads Cancellation
GetAsync Path; path plus dictionary or key/value query parameters Token-aware overloads
PostAsync Typed JSON, source-generated JSON metadata, multipart form data Token-aware overloads
PutAsync Typed JSON, source-generated JSON metadata, multipart form data, empty body Token-aware overloads
DeleteAsync Path Token-aware overload

Legacy overloads without a CancellationToken remain available, but request-scoped code should pass its token explicitly.

Authentication and headers

Generated adapters support None, Bearer, Basic, ApiKey, OAuth, and Identity auth metadata. Runtime adapters can use AddAccessToken, AddAccessTokenFunc, SetAuthorizationHeader, AddRequestHeader, SetOrReplaceHeader, SetHeaders, and the specialized language, user-agent, and cache-control helpers.

[AdapterHeader] is preferable for endpoint-specific values because the generator applies it to the individual HttpRequestMessage; default headers live on the shared typed HttpClient and affect later calls from that adapter instance.

Ping and warm-up

Adapters ping adapter/ping by default. Configure a different remote path with [AdapterPing("health")] or UsePing("health"), or opt out with [AdapterDisablePing] / DisablePing().

An ASP.NET Core service can expose the matching local endpoint and optionally keep registered adapters warm:

app.UseAdapterPing();
app.UseWarmUpAdapters(
    duration: TimeSpan.FromMinutes(30),
    interval: 300);

Warm-up starts background pings for adapters registered through AddServiceAdapter<T>(). Treat it as a serverless cold-start tool, not a replacement for platform health checks.

Response helpers

Helper Purpose
ReceiveJsonAsync<T>() Deserialize JSON using compatibility/reflection serialization
ReceiveJsonAsync(JsonTypeInfo<T>) Deserialize JSON with source-generated metadata; preferred for trim/AOT
ReceiveStringAsync() Read a raw response body
ReadProblemDetailsAsync() Parse RFC-style problem details
GetErrors() Convert ValidationProblemDetails into ModelStateDictionary

Dispose each HttpResponseMessage after reading it. Do not dispose a DI-managed HttpClient; pass shouldDisposeHttpClient: false from adapters created by IHttpClientFactory.

Generated endpoint metadata

The generator recognizes these contract attributes:

Attribute Scope Documentation meaning
AdapterEndpoint Method Verb, path, content type, auth override, error policy, query template, response envelope
AdapterHeader Method Per-request header and value template
AdapterAuth Class Default auth scheme and credential mappings
OAuthClientCredentials Class Token endpoint, credentials, scopes, expiry buffer
AdapterBaseUrl Class Default base URL property on the settings object
AdapterPing / AdapterDisablePing Class Remote liveness behavior
AdapterDependency Class Extra constructor dependency to include in generated documentation
AdapterJsonSerializerContext Class Source-generated JSON context used by endpoint bodies

See the annotations reference for every property, error behavior, analyzer diagnostic, authentication example, and generated-file shape.

Documentation artifacts

Every build containing generated adapter endpoints can emit two integration artifacts:

Artifact Consumer
{AssemblyName}.adapterschema.md Humans, internal docs portals, and AI documentation tooling
{AssemblyName}.adapteropenapi.json Swagger UI, Redoc, Postman, Insomnia, NSwag, and OpenAPI Generator

The source generator derives both artifacts from endpoint signatures, XML comments, DTO shapes, route/query/header templates, auth attributes, and response metadata. For useful output:

  1. Add XML <summary>, <param>, <returns>, <remarks>, and <example> comments to public adapter methods and DTOs.
  2. Use domain names such as CreateShipmentRequest, not generic names such as RequestModel.
  3. Model route and query values as typed parameters or DTO properties so the generator can document them.
  4. Declare response wrappers with ResponseWrapper and UnwrapProperty rather than hiding envelope behavior in prose.
  5. Declare non-obvious dependencies with [AdapterDependency].

Generated adapter classes must remain unsealed because the generator emits virtual endpoint and lifecycle hooks. Declare them as public partial class, not public sealed partial class.

Store settings-backed base URLs without a trailing slash when endpoint paths begin with one in generated interpolation. This avoids producing a double-slash path such as https://api.example.com//v1/orders.

Output directories and opt-outs are configurable in the consuming project:

<PropertyGroup>
  <AdapterSchemaOutputDir>docs/generated</AdapterSchemaOutputDir>
  <AdapterOpenApiOutputDir>docs/generated/openapi</AdapterOpenApiOutputDir>
  <GenerateAdapterSchema>true</GenerateAdapterSchema>
  <GenerateAdapterOpenApi>true</GenerateAdapterOpenApi>
</PropertyGroup>

Production checklist

  • Store credentials in a secret provider or environment-backed configuration, never in source.
  • Pass request cancellation tokens through every adapter call.
  • Set an HttpClient.Timeout appropriate to the upstream service.
  • Make retried write endpoints idempotent.
  • Prefer [AdapterJsonSerializerContext] and JsonTypeInfo<T> overloads for trimming and Native AOT.
  • Choose ErrorBehavior deliberately; document whether missing resources return null or throw.
  • Avoid logging authorization headers, secrets, or full sensitive payloads.
  • Test success, validation failure, rate limit, timeout, cancellation, and malformed-response paths.

Runnable example

The Adapter sample models a parcel-carrier integration with API-key authentication, idempotency, route parameters, generated Markdown/OpenAPI artifacts, DI registration, and a fake upstream handler so it can run without external credentials.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  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.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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
3.7.6 86 7/18/2026
3.7.5 125 7/13/2026
3.7.4 90 7/11/2026
3.7.3 89 7/11/2026
3.7.2 100 7/10/2026
3.7.1 99 7/9/2026
3.7.0 89 7/9/2026
3.6.4 97 7/9/2026