简介
Sparkdo.Mediation.Http 是 Sparkdo.Mediation 的 HTTP 扩展库,将中介者(Mediator)模式的 CQRS 调度能力延伸到 HTTP 调用场景。通过统一的 IHttpRequest<TResponse> / IHttpRequestHandler<T, TResponse> 消息模型,将 HTTP 请求的构建、发送与响应解析封装为可测试、可组合的消息处理管道。
该库基于 IHttpClientFactory 管理 HttpClient 生命周期,内置 System.Text.Json 序列化抽象,支持按类型自定义序列化选项、源码生成器(Source Generator)驱动的 JsonSerializerContext,以及 Sparkdo 模块系统的自动注册。
核心特性
1. HTTP 请求消息模型
- 三阶段生命周期:
CreateClient(获取 HttpClient)→ Request(构建 HttpRequestMessage)→ Response(解析 HttpResponseMessage)
- 上下文结构体:
HttpClientCreateContext、HttpRequestContext、HttpResponseContext 三个 readonly struct 传递各阶段所需数据,避免装箱分配
2. 两层基类体系
HttpRequest<TResponse>:轻量级抽象基类,仅定义三个生命周期方法,默认使用命名客户端 "Sparkdo.Mediation.Http"
SdkHttpRequest<TResponse>:SDK 级基类,自动从 DI 容器延迟注入 ILogger 和 IHttpJsonSerializer,提供可覆写的初始化钩子
3. 可扩展 JSON 序列化
IHttpJsonSerializer:序列化抽象接口,支持泛型与非泛型反序列化
DefaultHttpJsonSerializer:基于 System.Text.Json 的默认实现,按类型缓存 JsonSerializerOptions
HttpJsonSerializerOptions:流式配置 API,支持按类型条件配置序列化选项、注册 JsonSerializerContext 和自定义 IJsonTypeInfoResolver
4. 开放泛型处理器
HttpRequestHandler<THttpRequest, THttpResponse> 作为开放泛型处理器,统一编排 HTTP 请求的三阶段调用
- 通过
[GenericHandler] 程序集特性自动关联 IHttpRequest<,> 与 IHttpRequestHandler<,>
5. 模块化自动注册
SparkdoMediationHttpModule 在 PreConfigure 阶段自动调用 UseHttp()
UseHttp() 幂等注册开放泛型处理器和默认 JSON 序列化器
AddHttpHandlerConfiguration<TRequest, TResponse>() 将具体 HTTP 请求类型注册到 Mediator 管道
NuGet 包
| 属性 |
值 |
| 包 ID |
Sparkdo.Mediation.Http |
| 描述 |
Sparkdo 中介者模式 HTTP 扩展,将 CQRS 消息调度能力延伸到 HTTP 调用场景 |
| 目标框架 |
net10.0 |
| 依赖 |
Sparkdo.Mediation, Microsoft.Extensions.Http |
| 标签 |
mediator http cqrs sdk sparkdo |
| 许可证 |
按仓库根目录 LICENSE 文件 |
安装
Package Manager
Install-Package Sparkdo.Mediation.Http
.NET CLI
dotnet add package Sparkdo.Mediation.Http
PackageReference
<PackageReference Include="Sparkdo.Mediation.Http" Version="1.0.0" />
NuGet 包包含
| 文件 |
说明 |
lib/net10.0/Sparkdo.Mediation.Http.dll |
主程序集 |
lib/net10.0/Sparkdo.Mediation.dll |
传递依赖 — Sparkdo 中介者核心 |
README.md |
包自述文档 |
快速入门
1. 定义 HTTP 请求
using Sparkdo.Mediation.Http;
// 定义 HTTP 请求消息(使用轻量基类)
public class GetUserHttpRequest : HttpRequest<UserDto>
{
private readonly int _userId;
public GetUserHttpRequest(int userId) => _userId = userId;
public override ValueTask Request(HttpRequestContext context)
{
context.Message.Method = HttpMethod.Get;
context.Message.RequestUri = new Uri($"https://api.example.com/users/{_userId}");
return default;
}
public override async ValueTask<UserDto> Response(HttpResponseContext context)
{
var json = await context.Message.Content.ReadAsStringAsync(context.CancellationToken);
return JsonSerializer.Deserialize<UserDto>(json)!;
}
}
// 定义 HTTP 请求消息(使用 SDK 基类,自动注入 ILogger 和 IHttpJsonSerializer)
public class CreateUserHttpRequest : SdkHttpRequest<UserDto>
{
private readonly CreateUserPayload _payload;
public CreateUserHttpRequest(CreateUserPayload payload) => _payload = payload;
public override async ValueTask Request(HttpRequestContext context)
{
context.Message.Method = HttpMethod.Post;
context.Message.RequestUri = new Uri("https://api.example.com/users");
context.Message.Content = new StringContent(
JsonSerializer.Serialize(_payload),
Encoding.UTF8,
"application/json");
Logger.LogInformation("准备创建用户: {Email}", _payload.Email);
}
public override async ValueTask<UserDto> Response(HttpResponseContext context)
{
var json = await context.Message.Content.ReadAsStringAsync(context.CancellationToken);
return JsonSerializer.Deserialize<UserDto>(json)!;
}
}
2. 注册服务
// 方式一:手动注册
builder.Services.AddMediator(mediator =>
{
mediator.UseHttp();
mediator.AddHttpHandlerConfiguration<GetUserHttpRequest, UserDto>();
mediator.AddHttpHandlerConfiguration<CreateUserHttpRequest, UserDto>();
});
// 方式二:使用模块自动注册
// SparkdoMediationHttpModule 会在 PreConfigure 阶段自动调用 UseHttp()
// 只需通过源码生成器或手动注册具体的 HandlerConfiguration
public class UserService
{
private readonly IMediator _mediator;
public UserService(IMediator mediator) => _mediator = mediator;
public async Task<UserDto> GetUser(int userId)
{
return await _mediator.SendAsync<UserDto>(new GetUserHttpRequest(userId));
}
public async Task<UserDto> CreateUser(CreateUserPayload payload)
{
return await _mediator.SendAsync<UserDto>(new CreateUserHttpRequest(payload));
}
}
4. 实现自定义处理器
// 通常无需自定义处理器 — HttpRequestHandler<,> 作为开放泛型处理器
// 自动编排三阶段调用。如需扩展,可实现 IHttpRequestHandler<,>:
public class CustomHttpHandler<THttpRequest, THttpResponse>
: HttpRequestHandler<THttpRequest, THttpResponse>
where THttpRequest : IHttpRequest<THttpResponse>
{
public CustomHttpHandler(
IHttpClientFactory httpClientFactory,
IServiceProvider serviceProvider)
: base(httpClientFactory, serviceProvider) { }
public override async ValueTask<THttpResponse> HandleAsync(
THttpRequest request, CancellationToken cancellationToken = default)
{
// 自定义前置逻辑
var result = await base.HandleAsync(request, cancellationToken);
// 自定义后置逻辑
return result;
}
}
核心功能
HTTP 请求三阶段生命周期
CreateClient → Request → SendAsync → Response
| 阶段 |
方法 |
上下文 |
职责 |
| 创建客户端 |
CreateClient(HttpClientCreateContext) |
IServiceProvider, IHttpClientFactory |
获取或配置 HttpClient 实例 |
| 构建请求 |
Request(HttpRequestContext) |
IServiceProvider, HttpRequestMessage, CancellationToken |
设置 HTTP 方法、URI、请求头、内容 |
| 解析响应 |
Response(HttpResponseContext) |
IServiceProvider, HttpResponseMessage, CancellationToken |
解析响应体,处理状态码、错误 |
自定义 HttpClient
public class AuthenticatedHttpRequest<TResponse> : HttpRequest<TResponse>
{
public override ValueTask<HttpClient> CreateClient(HttpClientCreateContext context)
{
var client = context.HttpClientFactory.CreateClient("Authenticated");
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", GetToken(context.RequestServices));
return new ValueTask<HttpClient>(client);
}
public override ValueTask Request(HttpRequestContext context) => default;
public override ValueTask<TResponse> Response(HttpResponseContext context) => default!;
}
JSON 序列化配置
// 按类型自定义序列化选项
builder.Services.Configure<HttpJsonSerializerOptions>(options =>
{
// 针对特定类型配置
options.Configure<UserDto>(opt =>
{
opt.PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower;
});
// 按条件配置
options.Configure(
type => type.Namespace?.StartsWith("MyApp.Sdk") == true,
opt => opt.DefaultIgnoreCondition = JsonIgnoreCondition.Never);
// 添加源码生成器上下文
options.AddJsonSerializerContext(MyAppJsonSerializerContext.Default);
// 添加自定义 TypeInfoResolver
options.AddTypeInfoResolver(new DefaultJsonTypeInfoResolver());
});
SDK 请求初始化钩子
public class MySdkRequest : SdkHttpRequest<MyResponse>
{
protected override ValueTask InitializeAsync(IServiceProvider serviceProvider)
{
// 在 Request 调用前执行,可用于一次性初始化
return default;
}
protected override ValueTask InitializeRequestMessageAsync(
HttpRequestMessage message, CancellationToken cancellationToken)
{
// 为每个请求设置通用头
message.Headers.Add("X-Request-Id", Guid.NewGuid().ToString("N"));
return default;
}
protected override ValueTask InitializeLoggerAsync(IServiceProvider serviceProvider)
{
// 自定义日志记录器初始化
return base.InitializeLoggerAsync(serviceProvider);
}
public override ValueTask Request(HttpRequestContext context) => default;
public override ValueTask<MyResponse> Response(HttpResponseContext context) => default!;
}
API 参考
IHttpRequest<THttpResponse>
| 方法 |
说明 |
CreateClient(HttpClientCreateContext) |
创建或获取 HttpClient 实例 |
Request(HttpRequestContext) |
构建 HttpRequestMessage |
Response(HttpResponseContext) |
解析 HttpResponseMessage 并返回响应 |
HttpClientCreateContext
| 属性 |
说明 |
RequestServices |
请求级别的 IServiceProvider |
HttpClientFactory |
IHttpClientFactory 实例 |
HttpRequestContext
| 属性 |
说明 |
RequestServices |
请求级别的 IServiceProvider |
Message |
待发送的 HttpRequestMessage |
CancellationToken |
取消令牌 |
HttpResponseContext
| 属性 |
说明 |
RequestServices |
请求级别的 IServiceProvider |
Message |
收到的 HttpResponseMessage |
CancellationToken |
取消令牌 |
HttpRequest<THttpResponse>
| 成员 |
说明 |
CreateClient(HttpClientCreateContext) |
虚方法,默认使用命名客户端 "Sparkdo.Mediation.Http" |
Request(HttpRequestContext) |
抽象方法,构建请求 |
Response(HttpResponseContext) |
抽象方法,解析响应 |
SdkHttpRequest<TResponse>
| 成员 |
说明 |
Logger |
可覆写的 ILogger 属性,默认 NullLogger |
JsonSerializer |
可覆写的 IHttpJsonSerializer 属性 |
InitializeAsync(IServiceProvider) |
虚方法,请求前的初始化钩子 |
InitializeRequestMessageAsync(HttpRequestMessage, CancellationToken) |
虚方法,设置通用请求头等 |
InitializeLoggerAsync(IServiceProvider) |
虚方法,延迟初始化 Logger |
InitializeJsonSerializerAsync(IServiceProvider) |
虚方法,延迟初始化 JsonSerializer |
IHttpJsonSerializer
| 方法 |
说明 |
Serialize(object) |
序列化对象为 JSON 字符串 |
Deserialize<T>(string) |
反序列化 JSON 为指定类型 |
Deserialize(Type, string) |
反序列化 JSON 为运行时类型 |
HttpJsonSerializerOptions
| 属性/方法 |
说明 |
Default |
默认的 JsonSerializerOptions(Web 默认值、camelCase 等) |
Configurators |
按类型条件的配置器列表 |
TypeInfoResolvers |
自定义 IJsonTypeInfoResolver 列表 |
GetOptions(Type) |
获取指定类型的合并后 JsonSerializerOptions |
Configure<T>(Action<JsonSerializerOptions>) |
为特定类型添加配置 |
Configure(Func<Type, bool>, Action<JsonSerializerOptions>) |
为满足条件的类型添加配置 |
AddJsonSerializerContext(JsonSerializerContext) |
添加源码生成器上下文 |
AddTypeInfoResolver(IJsonTypeInfoResolver) |
添加自定义解析器 |
| 方法 |
说明 |
UseHttp() |
幂等注册开放泛型 IHttpRequestHandler<,> 和默认 IHttpJsonSerializer |
AddHttpHandlerConfiguration<TRequest, TResponse>() |
将具体 IHttpRequest<TResponse> 注册到 Mediator 管道 |
架构说明
IHttpRequest<TResponse>
├── HttpRequest<TResponse> (抽象基类,三阶段生命周期)
│ └── SdkHttpRequest<TResponse> (SDK 基类,DI 注入 + 初始化钩子)
└── 自定义实现
IHttpRequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
└── HttpRequestHandler<TRequest, TResponse> (开放泛型处理器)
├── 调用 request.Request(ctx) → 构建 HttpRequestMessage
├── 调用 request.CreateClient(ctx) → 获取 HttpClient
├── 发送 HTTP 请求
└── 调用 request.Response(ctx) → 解析响应
序列化层
IHttpJsonSerializer
└── DefaultHttpJsonSerializer
└── HttpJsonSerializerOptions
├── 按类型 JsonSerializerOptions 缓存
├── 条件配置器
└── TypeInfoResolver 链(支持 JsonSerializerContext)
测试
HTTP 请求处理器通过 IHttpClientFactory 抽象后,可在集成测试中 mock HttpClient:
// 使用 MockHttpMessageHandler 或 NSubstitute mock IHttpClientFactory
var handler = new HttpRequestHandler<GetUserHttpRequest, UserDto>(
mockHttpClientFactory,
serviceProvider);
var result = await handler.HandleAsync(new GetUserHttpRequest(1));
result.ShouldNotBeNull();