Eternet.Client.Http.Generator
2.0.6
Prefix Reserved
See the version list below for details.
dotnet add package Eternet.Client.Http.Generator --version 2.0.6
NuGet\Install-Package Eternet.Client.Http.Generator -Version 2.0.6
<PackageReference Include="Eternet.Client.Http.Generator" Version="2.0.6"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="Eternet.Client.Http.Generator" Version="2.0.6" />
<PackageReference Include="Eternet.Client.Http.Generator"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add Eternet.Client.Http.Generator --version 2.0.6
#r "nuget: Eternet.Client.Http.Generator, 2.0.6"
#:package Eternet.Client.Http.Generator@2.0.6
#addin nuget:?package=Eternet.Client.Http.Generator&version=2.0.6
#tool nuget:?package=Eternet.Client.Http.Generator&version=2.0.6
Eternet.Client.Http.Generator
Generador incremental para crear handlers HTTP a partir de contratos Eternet.Mediator.
Soporta el caso clásico de un solo HttpClient por contrato y, además, el escenario de API Gateway con:
- múltiples transportes por cliente (
Internal,Gateway) - ruta proyectada por namespace
- override de verbo HTTP en gateway
- selección dinámica en runtime sin ensuciar
Mediator
Paquetes
En la app consumidora:
<ItemGroup>
<PackageReference Include="Eternet.Mediator" Version="x.y.z" />
<PackageReference Include="Eternet.Client.Http.Generator" Version="x.y.z" PrivateAssets="all" />
</ItemGroup>
Si el contrato publica metadata de gateway:
<ItemGroup>
<PackageReference Include="Eternet.Models" Version="x.y.z" />
</ItemGroup>
Alternativa local en workspace:
<ItemGroup>
<ProjectReference Include="..\..\..\..\Eternet.AspNetCore\src\Eternet.Mediator\Eternet.Client.Http.Generator\Eternet.Client.Http.Generator.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
Caso simple
El uso existente no cambia:
using Eternet.Mediator;
using Eternet.Netmap.Contracts.Nodes.Commands;
[GenerateHttpClient("Default")]
internal abstract class DefaultHttpClient
{
internal abstract class AddNodeHandler : AddNode;
internal abstract class UpdateNodeHandler : UpdateNode;
}
El generator sigue emitiendo:
services.AddDefaultHttpClient(...)services.AddHttpClientHandlers()
Registro:
services.AddHttpClientHandlers();
services.AddDefaultHttpClient(
"https://internal-service/",
configure: client =>
{
client.DefaultRequestHeaders.Add("X-App", "Netmap");
},
configureBuilder: builder =>
{
builder.AddHttpMessageHandler<MyAuthHandler>();
});
Consumo:
public sealed class NodesViewModel(IGetResponse<AddNode.Response> response)
{
public ValueTask<AddNode.Response> CreateAsync(AddNode.Request request, CancellationToken ct)
=> response.Get(request, ct);
}
IGetResponse<TResponse> sigue usando el handler por defecto.
Múltiples transportes
Cuando el mismo contrato puede consumirse por el servicio interno o por API Gateway, repetí GenerateHttpClient con distinto transporte:
using Eternet.Mediator;
[GenerateHttpClient("Default", Transport = HttpClientTransport.Internal)]
[GenerateHttpClient("Default", Transport = HttpClientTransport.Gateway)]
internal abstract class DefaultHttpClient
{
internal abstract class GetProductHandler : GetProduct;
}
El generator produce:
services.AddDefaultHttpClient(...)services.AddDefaultHttpClientInternal(...)services.AddDefaultHttpClientGateway(...)
Registros típicos:
services.AddHttpClientHandlers();
services.AddDefaultHttpClientInternal(
"https://internal-service/",
configure: client =>
{
client.DefaultRequestHeaders.Add("X-Transport", "internal");
},
configureBuilder: builder =>
{
builder.AddHttpMessageHandler<InternalAuthHandler>();
builder.AddPolicyHandler(InternalRetryPolicy.Create());
});
services.AddDefaultHttpClientGateway(
"https://api-gateway/",
configure: client =>
{
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", "gateway-token");
},
configureBuilder: builder =>
{
builder.AddHttpMessageHandler<GatewayAuthHandler>();
});
La sobrecarga configureBuilder existe para que el helper generado no limite la configuración del IHttpClientBuilder.
Proyecciones de API Gateway
ApiGatewayEndpointAttribute vive en Eternet.Models.Attributes y modela la proyección publicada por gateway:
using Eternet.Mediator;
using Eternet.Mediator.Abstractions.Handlers;
using Eternet.Mediator.Attributes.Mvc;
using Eternet.Models;
using Eternet.Models.Attributes;
[GenerateEndpoint("Products")]
public abstract class GetProduct
: DomainResultHandlerAsync<GetProduct.Request, GetProduct.Response>
{
public record Request : CreateEntityCommand<Response>
{
[FromRoute] public required int Id { get; init; }
}
public record Response : CreateEntityDomainResult
{
public string Name { get; init; } = string.Empty;
}
[HttpGet("Internal/{id}")]
[ApiGatewayEndpoint(OperationNamespace.Customers, "Public/Products/{id}", HttpMethod = "POST")]
[ApiGatewayEndpoint(OperationNamespace.Billing, "BillingProducts/{id}")]
public abstract override ValueTask<Response> Handle(
Request request,
CancellationToken cancellationToken);
}
Soporte actual:
- transporte
InternaloGateway - namespace publicado en gateway
- route override
- HTTP method override
No soporta todavía transformaciones arbitrarias del body ni rename de parámetros.
Selección en runtime
Para el path por defecto seguí usando IGetResponse<TResponse>:
public sealed class InternalProductsViewModel(IGetResponse<GetProduct.Response> response)
{
public ValueTask<GetProduct.Response> LoadAsync(GetProduct.Request request, CancellationToken ct)
=> response.Get(request, ct);
}
Para elegir gateway en runtime usá IGetResponseFactory:
public sealed class GatewayProductsViewModel(
IGetResponseFactory responseFactory)
{
public ValueTask<GetProduct.Response> LoadCustomersAsync(
GetProduct.Request request,
CancellationToken ct)
{
return responseFactory
.Gateway<GetProduct.Response>(OperationNamespace.Customers)
.Get(request, ct);
}
public ValueTask<GetProduct.Response> LoadBillingAsync(
GetProduct.Request request,
CancellationToken ct)
{
return responseFactory
.Gateway<GetProduct.Response>(OperationNamespace.Billing)
.Get(request, ct);
}
public ValueTask<GetProduct.Response> LoadInternalAsync(
GetProduct.Request request,
CancellationToken ct)
{
return responseFactory
.Internal<GetProduct.Response>()
.Get(request, ct);
}
}
Con eso:
IGetResponse<TResponse>queda para el flujo defaultIGetResponseFactorypermite elegir el transporte y el namespace de gateway en runtime- el handler generado resuelve
HttpClient, ruta y verbo a partir del contexto y los atributos
Qué genera el runtime
Para contratos con múltiples transportes o proyecciones de gateway, el handler generado:
- resuelve el
HttpClientreal a usar - proyecta la ruta final (
InternaloGateway/{namespace}/...) - proyecta el verbo final (
GET,POST, etc.) - mantiene un único
RequestClassHandlerWrapper<TRequest, TResponse>
Esto evita duplicar registros de Mediator para el mismo request.
Referencia rápida
GenerateHttpClientAttribute: nombre lógico del cliente y transporteHttpClientTransport:Internal,GatewayApiGatewayEndpointAttribute: namespace, route yHttpMethodIGetResponse<TResponse>: consumo defaultIGetResponseFactory: selección explícita de transporte en runtime
Ver también
Learn more about Target Frameworks and .NET Standard.
This package has no dependencies.
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.1.10 | 0 | 4/23/2026 |
| 2.1.9 | 83 | 4/13/2026 |
| 2.1.8 | 93 | 4/13/2026 |
| 2.1.7 | 83 | 4/12/2026 |
| 2.1.6 | 81 | 4/12/2026 |
| 2.1.5 | 87 | 4/10/2026 |
| 2.1.4 | 112 | 4/3/2026 |
| 2.1.3 | 88 | 4/2/2026 |
| 2.1.2 | 100 | 3/31/2026 |
| 2.1.1 | 99 | 3/30/2026 |
| 2.1.0 | 81 | 3/30/2026 |
| 2.0.7 | 95 | 3/27/2026 |
| 2.0.6 | 101 | 3/21/2026 |
| 2.0.5 | 89 | 3/21/2026 |
| 2.0.4 | 85 | 3/20/2026 |
| 2.0.3 | 88 | 3/20/2026 |
| 2.0.2 | 90 | 3/18/2026 |
| 2.0.1 | 85 | 3/18/2026 |
| 1.2.13 | 100 | 3/10/2026 |
| 1.2.12 | 88 | 3/9/2026 |