XiHan Framework 处于预览阶段

查看获取方式
跳转到内容

快速上手 ​

本页从取得预览包开始,建一个 ASP.NET Core 应用,写一个操作契约并经 HTTP 调用它,再换成 Standard 组合观察能力图谱与管道。适合第一次使用框架的开发者,全程约 15 分钟。

环境准备 ​

项要求
.NET SDK.NET 10 SDK;从源码构建框架时用仓库 global.json 锁定的 10.0.4xx 功能带
Git从源码引用时克隆 XiHan.Framework 仓库
编辑器Visual Studio 2026、Rider 或 VS Code(C# Dev Kit)

获取预览包 ​

预览包在 nuget.org 上,直接引用即可;要调试框架源码,或者验证还没发布的改动,用后两种方式。框架源码在 XiHan.Framework 仓库。三种方式任选其一。

方式一:NuGet ​

适合只使用框架、不改框架源码的场景。

bash
dotnet add package XiHan.Framework.Profiles.Minimal --prerelease
dotnet add package XiHan.Framework.Protocols.Http --prerelease
dotnet add package XiHan.Framework.Kernel.Generators --prerelease

方式二:源码引用 ​

适合同时调试框架源码的场景。

  1. 克隆仓库:

    bash
    git clone --branch dev https://github.com/XiHanFun/XiHan.Framework.git
    cd XiHan.Framework
  2. 需要构建整个解决方案时初始化规范子模块(Plugins.Protocol 从 framework/spec/plugin/plugin.proto 生成代码):

    bash
    git submodule update --init framework/spec
  3. 应用项目以 ProjectReference 引用 framework/src 下的项目,源生成器按分析器引用:

    xml
    <ItemGroup>
      <ProjectReference Include="../XiHan.Framework/framework/src/XiHan.Framework.Profiles.Minimal/XiHan.Framework.Profiles.Minimal.csproj" />
      <ProjectReference Include="../XiHan.Framework/framework/src/XiHan.Framework.Protocols.Http/XiHan.Framework.Protocols.Http.csproj" />
      <ProjectReference Include="../XiHan.Framework/framework/src/XiHan.Framework.Kernel.Generators/XiHan.Framework.Kernel.Generators.csproj"
                        OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
    </ItemGroup>

方式三:本地包源 ​

适合验证还没发布的改动的场景。

  1. 在仓库根还原、构建并打包(打包前先按方式二的第 2 步初始化子模块):

    bash
    dotnet restore framework/XiHan.Framework.slnx
    dotnet build framework/XiHan.Framework.slnx -c Release --no-restore
    dotnet pack framework/XiHan.Framework.slnx -c Release --no-build

    包写到 framework/artifacts/packages/,文件名形如 XiHan.Framework.Kernel.<版本>.nupkg。

  2. 在应用的解决方案目录放一个 nuget.config,把这个目录登记为包源:

    xml
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <packageSources>
        <add key="xihan-local" value="../XiHan.Framework/framework/artifacts/packages" />
      </packageSources>
    </configuration>
  3. 在应用项目里添加引用:

    bash
    dotnet add package XiHan.Framework.Profiles.Minimal --prerelease
    dotnet add package XiHan.Framework.Protocols.Http --prerelease
    dotnet add package XiHan.Framework.Kernel.Generators --prerelease

Kernel.Generators 是开发期依赖,只在编译时运行,不进入应用的运行时依赖。

第一步:创建项目 ​

bash
dotnet new web -n HelloXiHan
cd HelloXiHan

按上一节任一方式加入三个引用:Profiles.Minimal(内核、ASP.NET Core 宿主与内存本地化)、Protocols.Http(HTTP 协议适配器)、Kernel.Generators(操作源生成器)。项目文件里确认 RootNamespace 为 HelloXiHan,生成的登记代码放在这个命名空间下。

第二步:写操作契约 ​

新建 Greet.cs。操作 ID greetings.create 的资源是 greetings、动词是 create,HTTP 适配器据此推导出 POST /greetings:

csharp
using XiHan.Framework.Kernel.Operations;
using XiHan.Framework.Primitives;

namespace HelloXiHan;

[Operation(Id, Stability = Stability.Experimental, Expose = Expose.Http)]
public sealed class Greet : IOperation<GreetRequest, GreetResponse>
{
    public const string Id = "greetings.create";

    public ValueTask<Result<GreetResponse>> HandleAsync(GreetRequest request, InvocationContext context)
        => ValueTask.FromResult(Result.Success(new GreetResponse($"Hello, {request.Name}!", context.TraceId)));
}

public sealed record GreetRequest(string Name);

public sealed record GreetResponse(string Message, string TraceId);

HandleAsync 返回 Result<GreetResponse>:可恢复的失败返回 Error,不抛异常。

第三步:登记序列化类型 ​

内核不经反射序列化。新建 AppJsonContext.cs,把请求与响应类型登记到源生成的序列化上下文;Kernel.Generators 从这里取类型元数据,类型没有登记时报 XHG002:

csharp
using System.Text.Json.Serialization;

namespace HelloXiHan;

[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase, PropertyNameCaseInsensitive = true)]
[JsonSerializable(typeof(GreetRequest))]
[JsonSerializable(typeof(GreetResponse))]
internal sealed partial class AppJsonContext : JsonSerializerContext;

第四步:写特性 ​

新建 GreetingsFeature.cs。清单声明这个特性只依赖内核的宿主能力,Configure 调用源生成器产出的 AddGeneratedOperations 登记操作与它的 JSON Schema:

csharp
using XiHan.Framework.Kernel;
using XiHan.Framework.Kernel.Hosting;
using XiHan.Framework.Primitives;
using XiHan.Framework.Primitives.Manifests;

namespace HelloXiHan;

public sealed class GreetingsFeature : IFeature
{
    public Manifest Manifest { get; } = new()
    {
        Id = "xihan.hello.greetings",
        Package = "HelloXiHan",
        Version = "1.0.0",
        Primitives = 1,
        Stability = Stability.Experimental,
        Kind = ManifestKind.Capability,
        Requires = [new CapabilityRequirement(KernelCapabilities.Hosting, KernelCapabilities.Version)],
        Entry = typeof(GreetingsFeature).FullName,
    };

    public void Configure(FeatureContext context) => context.AddGeneratedOperations();
}

第五步:改写 Program.cs ​

csharp
using HelloXiHan;
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.Profiles.Minimal;
using XiHan.Framework.Protocols.Http;
using XiHan.Framework.Protocols.Http.Routing;

var builder = WebApplication.CreateBuilder(args);

// 把特性交给内核:求解能力图谱,按拓扑顺序调用各特性的 Configure
builder.AddXiHan(xihan => xihan
    .UseMinimalProfile()
    .UseFeature<HttpProtocolFeature>()
    .UseFeature<GreetingsFeature>());

var app = builder.Build();

app.UseXiHan();            // HTTP 请求进入内核管道
app.MapXiHanHealth();      // /health/startup、/health/ready、/health/live
app.MapXiHanOperations();  // 按操作登记表映射路由

app.Run();

第六步:运行 ​

bash
dotnet run --urls http://localhost:5000

启动日志先打印已解析的能力图谱,再打印管道顺序:

text
Capability graph:
xihan.kernel.core <版本>
  provides kernel.hosting@1
  ...
xihan.localization.inmemory <版本> (default)
  provides localization.resources@1
  requires kernel.hosting@1 -> xihan.kernel.core
xihan.protocols.http <版本>
  provides protocols.http@1
  requires kernel.hosting@1 -> xihan.kernel.core
xihan.hello.greetings 1.0.0
  requires kernel.hosting@1 -> xihan.kernel.core

Pipeline:
observe      XiHan.Framework.Kernel.Diagnostics.ObserveMiddleware
resilience   XiHan.Framework.Kernel.Pipeline.DeadlineMiddleware
resilience   XiHan.Framework.Kernel.Resilience.ResilienceMiddleware
validate     XiHan.Framework.Kernel.Validation.ValidationMiddleware

调用操作:

bash
curl -i -X POST http://localhost:5000/greetings -H "Content-Type: application/json" -d '{"name":"Ada"}'
text
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8

{"message":"Hello, Ada!","traceId":"c4a453046dcf9b7fac181cb8d5475014"}

请求不满足契约时,Validate 阶段按生成的 JSON Schema 拒绝,宿主按 Accept-Language 翻译成 RFC 9457 Problem Details:

bash
curl -i -X POST http://localhost:5000/greetings -H "Content-Type: application/json" -H "Accept-Language: zh-CN" -d '{}'
text
HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
Content-Language: zh-CN

{"type":"urn:xihan:error:KERNEL_VALIDATION_003","title":"VALIDATION","status":400,
 "detail":"操作 'greetings.create' 的请求不符合契约:$.name: required property 'name' is missing",
 "instance":"/greetings","code":"KERNEL_VALIDATION_003","traceId":"…",
 "errors":{"name":["缺少必填属性 'name'"]},
 "details":{"id":"greetings.create","reason":"$.name: required property 'name' is missing"}}

/health/ready 返回应用状态与每个特性的状态,可直接作为就绪探针。

换成 Standard 组合 ​

把 Profiles.Minimal 换成 Profiles.Standard,UseMinimalProfile() 换成 UseStandardProfile(),应用多了持久化、缓存、多租户、安全与消息五个子系统的内存默认实现:

csharp
using HelloXiHan;
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.Profiles.Standard;
using XiHan.Framework.Protocols.Http;
using XiHan.Framework.Protocols.Http.Routing;

var builder = WebApplication.CreateBuilder(args);

builder.AddXiHan(xihan => xihan
    .UseStandardProfile()
    .UseFeature<HttpProtocolFeature>()
    .UseFeature<GreetingsFeature>());

var app = builder.Build();
app.UseXiHan();
app.MapXiHanHealth();
app.MapXiHanOperations();
app.Run();

管道里出现了各子系统贡献的中间件,顺序由阶段决定,与 UseFeature 的书写顺序无关:

text
observe      XiHan.Framework.Kernel.Diagnostics.ObserveMiddleware
resilience   XiHan.Framework.Kernel.Pipeline.DeadlineMiddleware
resilience   XiHan.Framework.Kernel.Resilience.ResilienceMiddleware
authenticate XiHan.Framework.Security.Abstractions.Authentication.AuthenticationMiddleware
tenant       XiHan.Framework.MultiTenancy.Abstractions.Resolution.TenantResolutionMiddleware
authorize    XiHan.Framework.Security.Abstractions.Authorization.AuthorizationMiddleware
validate     XiHan.Framework.Kernel.Validation.ValidationMiddleware
idempotency  XiHan.Framework.Caching.Abstractions.Idempotency.IdempotencyMiddleware
transaction  XiHan.Framework.Persistence.Abstractions.UnitOfWork.UnitOfWorkMiddleware

Greet 没有声明 Permission,Authorize 阶段直接放行,调用结果与前面相同。给操作加上 Permission = "greetings.write" 后,还要在特性里登记这个权限码,并在 XiHan:Security:InMemory 下配置主体与授予,做法见授权。

完整示例 ​

仓库的 framework/samples 下有几个零外部设施即可运行的示例:

示例内容
SimpleAppStandard 组合:订单的两个操作同时经 HTTP、gRPC 与 MCP 暴露,入站 CloudEvents 交给消息处理器,带租户、ApiKey 认证、权限、事务、领域事件与发件箱;Native AOT 冒烟项目
SimpleCliMinimal 组合:同一份契约作为命令行命令与 MCP stdio tool
KubernetesAppFull 组合:探针、停机宽限、ConfigMap 热更新、Lease 领导选举与 xihan pack 产物
SamplePlugin、EchoPlugin、EchoWasmPlugin、EchoGoPlugin、CacheGoPlugin进程内、进程外(.NET、Go)与 Wasm 插件
bash
dotnet run --project framework/samples/SimpleApp
curl -s -X POST localhost:5000/orders -H "Authorization: ApiKey dev-alice-key" -H "Content-Type: application/json" -d '{"name":"widget","amount":3}'

下一步 ​

  1. 能力包与清单:特性、清单与能力图谱
  2. 操作契约:操作 ID、暴露协议、授权要求与源生成器
  3. 执行管道:十一个阶段与中间件
  4. 包总览:按需选择 Provider

Released under The MIT License