XiHan Framework 处于预览阶段

查看获取方式
跳转到内容

XiHan.Framework.Hosting.AspNetCore ​

ASP.NET Core 宿主适配:把 HTTP 请求翻译成调用上下文并经内核管道执行,映射探针端点,用 RFC 9457 Problem Details 回写失败结果。所有 Web 形态的 XiHan 应用都用它承载,HTTP、gRPC、MCP、CloudEvents 协议适配器都建在它上面。

项内容
包 IDXiHan.Framework.Hosting.AspNetCore
环层Ring 4(宿主)
能力宿主本身不提供能力;可选的 HostedBlobUrlFeature 提供 objectstorage.presign@1,依赖 kernel.hosting@1、objectstorage.blob@1
特性入口—(可选 HostedBlobUrlFeature)
配置节环境变量 XIHAN_CONFIG_PATH;XiHan:ObjectStorage:SignedUrls(预签名地址特性);方案 XiHan 读 XiHan:Security:RoleClaim
依赖XiHan.Framework.Kernel、XiHan.Framework.Security.Abstractions、XiHan.Framework.Localization.Abstractions、XiHan.Framework.ObjectStorage.Abstractions;共享框架 Microsoft.AspNetCore.App
AOT兼容(IsAotCompatible)
稳定性UseXiHan、MapXiHanHealth、HttpInvocation、ProblemResponse、端点约定为 Stable;WebApplicationBuilder.AddXiHan、认证方案 XiHan、OperationPayloadBinder、OperationResponseWriter、预签名地址为 Preview

概述 ​

宿主不认证、不解析租户、不判定授权,只做协议到内核的翻译。UseXiHan() 是一个 ASP.NET Core 中间件:对每个请求,它从 traceparent、baggage、xihan-deadline(或 grpc-timeout)、Accept-Language、Authorization 建调用上下文,记下调用来源,把端点元数据上的授权要求与操作描述放进上下文,然后让其余的 ASP.NET Core 管道作为内核管道的 Handle 阶段执行;调用失败且响应尚未开始时写 Problem Details;调用成功而端点没有执行(幂等回放)时,用端点元数据上的 OperationResponseWriter 写出上下文里的响应。应用未就绪时直接回 503,带 PipelineBypassMetadata 的端点(探针、文档、gRPC 方法、SignalR Hub)不经内核管道。装配了授权能力(容器里有 PolicyCatalog)时,UseXiHan() 在宿主建请求管道时核对全部端点元数据上的授权要求:RequireXiHanPermission 的权限码未登记、RequireXiHanPolicy 的策略未注册,即抛出 SECURITY_VALIDATION_004(一次列出全部),app.StartAsync() / app.Run() 失败(ADR-0080)。

包里还有三块面向特定场景的能力:AddAuthentication().AddXiHan(...) 登记的 ASP.NET Core 认证方案 XiHan,让绕过管道的端点也用内核的认证处理器(ADR-0051);MapXiHanHealth() 的三个探针;HostedBlobUrlFeature 与 MapXiHanBlobs(),给没有原生签名的对象存储(文件系统)签预签名地址并代为收发(ADR-0049)。

何时使用 ​

用 WebApplication 承载 XiHan 应用时就需要它,Profiles.Minimal、Profiles.Standard、Profiles.Full 都已引用。只在命令行里运行的工具用 Hosting.CommandLine。要把操作契约发布成 REST 端点,再加 Protocols.Http。

安装与启用 ​

bash
dotnet add package XiHan.Framework.Hosting.AspNetCore --prerelease

当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。

csharp
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.Profiles.Standard;

var builder = WebApplication.CreateBuilder(args);
builder.AddXiHan(xihan => xihan.UseStandardProfile());

var app = builder.Build();
app.UseXiHan();          // 放在路由之后、端点之前
app.MapXiHanHealth();
app.Run();

配置 ​

键类型缺省说明
环境变量 XIHAN_CONFIG_PATH目录无挂载的配置目录:appsettings.json 最先,其余顶层 *.json 按文件名序数随后,紧接 appsettings.{环境}.json 插入(覆盖 appsettings,环境变量与命令行参数覆盖它),可重载
XiHan:Security:RoleClaimstringrole方案 XiHan 转出的 ClaimsPrincipal 的角色声明类型
XiHan:ObjectStorage:SignedUrls:Secretstring无,必填预签名地址的 HMAC-SHA256 密钥,至少 32 字节 UTF-8,多实例须一致
XiHan:ObjectStorage:SignedUrls:BaseUrlstring/blobs预签名地址的基址

后两项只在装配 HostedBlobUrlFeature 时读取。

json
{
  "XiHan": {
    "ObjectStorage": {
      "SignedUrls": {
        "Secret": "dev-signing-key-at-least-32-bytes-long",
        "BaseUrl": "/blobs"
      }
    }
  }
}

主要类型 ​

类型说明
WebApplicationBuilderExtensionsAddXiHan(configure):装载挂载的配置目录,再交给内核装配应用
ApplicationBuilderExtensionsUseXiHan():请求桥接进内核管道;MapXiHanHealth(prefix):{prefix}/startup、/ready、/live
Endpoints.HttpInvocationGetXiHanContext() 取当前调用上下文;CreateContext(httpContext) / CreateContext(httpContext, services) 按 HTTP 载体映射建上下文;AcceptedLocales、ParseBaggage、FormatBaggage;常量 DeadlineHeader、GrpcTimeoutHeader
Endpoints.EndpointConventionBuilderExtensionsRequireXiHanAuthentication()、RequireXiHanPermission(code, resource)、RequireXiHanPolicy(name, resource);引用的权限码与策略在宿主建请求管道时核对,不存在即启动失败
Endpoints.PipelineBypassMetadata端点元数据:带它的端点不经内核管道;BypassXiHanPipeline(builder) 标注
Endpoints.OperationPayloadBinder协议适配器挂在端点上的载荷绑定委托,UseXiHan() 在进管道前调用
Endpoints.OperationResponseWriter协议适配器挂在端点上的成功响应写出委托(状态码、内容类型与正文);幂等回放时端点不执行,UseXiHan() 在管道成功结束、响应未开始而上下文里有响应对象时用它写出
ProblemResponseProblem Details 响应体;FromError、StatusCodeFor、IsAuthenticationFailure、FieldErrorsOf、ScalarDetailsOf、WriteTo
Health.HealthResponse、Health.FeatureHealth探针响应体
Authentication.InvocationAuthenticationBuilderExtensionsAddXiHan(configure):登记 ASP.NET Core 认证方案 XiHan
Authentication.InvocationAuthenticationOptionsQueryTokenPaths:接受查询串 access_token 的路径前缀
Authentication.IInvocationAuthenticationFilter方案 XiHan 认证成功后的挂点(会话门禁)
Authentication.InvocationAuthenticationDefaults常量:方案名 XiHan、参数名 access_token、令牌方案 Bearer
Blobs.HostedBlobUrlFeature、Blobs.HostedBlobUrlSigner、Blobs.BlobEndpointRouteBuilderExtensions托管的预签名地址:特性、签名器(ForStore(name) 给命名实例签)、MapXiHanBlobs()(响应带 nosniff,内容除 PDF 外进沙箱,ADR-0125)

使用示例 ​

端点里读安全上下文、挂授权要求:

csharp
using XiHan.Framework.Hosting.AspNetCore.Endpoints;
using XiHan.Framework.Kernel.Security;
using XiHan.Framework.Primitives;

// 已认证才进得来:Authenticate 与 Tenant 阶段已写好安全上下文
app.MapGet("/me", (HttpContext http) =>
{
    var security = http.GetXiHanContext().ValueOrThrow().GetSecurity();
    return $"{security.Principal.Id}@{security.Tenant?.Id ?? "-"}";
}).RequireXiHanAuthentication();

静态资源等不需要内核管道、应用未就绪时也要能访问的端点:

csharp
using XiHan.Framework.Hosting.AspNetCore.Endpoints;

PipelineBypassMetadata.BypassXiHanPipeline(app.MapGet("/version", () => "1.0.0"));

SignalR Hub 的认证与在 Hub 里调用操作见实时通信。

行为与限制 ​

  • UseXiHan() 要在路由之后、端点之前;WebApplication 自动加的路由在管道开头,直接调用即可。需要真实客户端地址时,在它之前调用 UseForwardedHeaders()。
  • 成功的调用不改动响应;失败时只有响应尚未开始写出才写 Problem Details,端点已写正文时保留端点的内容。
  • baggage 只保留已登记的键,其中 xihan.tenant 与 xihan.principal 不收(ADR-0121),HttpInvocation.FormatBaggage 出站也只写已登记的键(RFC-0003 规则 3);traceparent 的采样标志进 TraceFlags,缺失或不合法时并入 ASP.NET Core 当前的请求 Activity(同一 trace-id),也没有时生成新的 trace-id;xihan-deadline 解析失败视为没有截止时间。
  • 查询串令牌只在 QueryTokenPaths 登记的前缀下接受,前缀不能为空或 /;方案 XiHan 只认带 PipelineBypassMetadata 的端点。
  • 调用来源 InvocationOrigin 记 http、方法与路径(含 PathBase,不含查询串)、连接对端地址、User-Agent 与 Referer,以及匹配到的端点的路由模板(Route)与名字(EndpointName,即 WithName),普通端点据此在 Observe 阶段被识别(ADR-0048)。
  • 健康探针的响应体含各特性状态与 IHealthContributor 条目(如每个进程外插件)的状态;条目另带 description、checkedAt、durationMs 与 data,有才写(ADR-0054)。
  • 预签名端点 GET <BaseUrl>/{container}/{**key} 下载(单个 Range 区间回 206,不可满足回 416,可带保存文件名),PUT 上传整个对象或分片的一片(响应 ETag);上传解除请求体大小上限,单对象上限由存储把关;端点经内核管道、不要求凭据。命名实例用 HostedBlobUrlSigner.ForStore(name) 签,地址带 x-store=<name>,实例名在签名里,实例不存在回 404(OBJECTSTORAGE_NOTFOUND_003,ADR-0050)。存储能自己签名(S3)时不要装本特性。
  • 在绕过管道的端点(SignalR Hub、Server-Sent Events)里发起内核调用用 HttpInvocation.CreateContext(httpContext, services):Authorization 头经 SetCredential 带上,经管道时重新认证。
  • Accept-Language 在调用方没有显式 xihan.locale Baggage 时按权重协商进该 Baggage(装配了本地化时协商到启用的区域,否则取第一个合法值);Problem Details 的 Content-Language 是实际命中的区域(可能是回退链上的区域),code 不变。
  • VALIDATION 种类的 Problem Details 带 errors(字段键 → 消息数组),所有错误按白名单带 details:Error.Details 里的字符串、布尔、数值、Guid、时间等标量,集合与对象不输出(ADR-0024)。
  • 挂载目录与用户机密的次序:配置源从低到高依次是 appsettings.json、appsettings.{环境}.json、XIHAN_CONFIG_PATH 挂载目录、用户机密(仅开发环境)、环境变量、命令行参数、应用自己添加的配置源;构建器没有 appsettings 文件源时挂载目录追加在末尾。xihan pack 生成的清单同时设 DOTNET_USE_POLLING_FILE_WATCHER=1(ConfigMap 以符号链接切换更新)。
  • Problem Details 由 ProblemResponse.WriteTo 手写、探针由源生成上下文序列化,不经反射。
情形状态码错误码
应用未就绪或正在停止503KERNEL_UNAVAILABLE_001
进入管道时截止时间已过504KERNEL_TIMEOUT_001
端点抛出未处理异常500KERNEL_UNEXPECTED_001
未认证 / 凭据无效401,带 WWW-AuthenticateSECURITY_DENIED_001 / SECURITY_DENIED_003
策略拒绝 / 缺少权限403SECURITY_DENIED_002 / SECURITY_DENIED_004
预签名地址无效或已过期403OBJECTSTORAGE_DENIED_001

状态码按错误码 KIND 的完整映射见 HTTP 与 OpenAPI。

相关 ​

Released under The MIT License