快速上手
本页从取得预览包开始,建一个 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
适合只使用框架、不改框架源码的场景。
dotnet add package XiHan.Framework.Profiles.Minimal --prerelease
dotnet add package XiHan.Framework.Protocols.Http --prerelease
dotnet add package XiHan.Framework.Kernel.Generators --prerelease方式二:源码引用
适合同时调试框架源码的场景。
克隆仓库:
bashgit clone --branch dev https://github.com/XiHanFun/XiHan.Framework.git cd XiHan.Framework需要构建整个解决方案时初始化规范子模块(
Plugins.Protocol从framework/spec/plugin/plugin.proto生成代码):bashgit submodule update --init framework/spec应用项目以
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>
方式三:本地包源
适合验证还没发布的改动的场景。
在仓库根还原、构建并打包(打包前先按方式二的第 2 步初始化子模块):
bashdotnet 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。在应用的解决方案目录放一个
nuget.config,把这个目录登记为包源:xml<?xml version="1.0" encoding="utf-8"?> <configuration> <packageSources> <add key="xihan-local" value="../XiHan.Framework/framework/artifacts/packages" /> </packageSources> </configuration>在应用项目里添加引用:
bashdotnet 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 是开发期依赖,只在编译时运行,不进入应用的运行时依赖。
第一步:创建项目
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:
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:
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:
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
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();第六步:运行
dotnet run --urls http://localhost:5000启动日志先打印已解析的能力图谱,再打印管道顺序:
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调用操作:
curl -i -X POST http://localhost:5000/greetings -H "Content-Type: application/json" -d '{"name":"Ada"}'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:
curl -i -X POST http://localhost:5000/greetings -H "Content-Type: application/json" -H "Accept-Language: zh-CN" -d '{}'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(),应用多了持久化、缓存、多租户、安全与消息五个子系统的内存默认实现:
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 的书写顺序无关:
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.UnitOfWorkMiddlewareGreet 没有声明 Permission,Authorize 阶段直接放行,调用结果与前面相同。给操作加上 Permission = "greetings.write" 后,还要在特性里登记这个权限码,并在 XiHan:Security:InMemory 下配置主体与授予,做法见授权。
完整示例
仓库的 framework/samples 下有几个零外部设施即可运行的示例:
| 示例 | 内容 |
|---|---|
SimpleApp | Standard 组合:订单的两个操作同时经 HTTP、gRPC 与 MCP 暴露,入站 CloudEvents 交给消息处理器,带租户、ApiKey 认证、权限、事务、领域事件与发件箱;Native AOT 冒烟项目 |
SimpleCli | Minimal 组合:同一份契约作为命令行命令与 MCP stdio tool |
KubernetesApp | Full 组合:探针、停机宽限、ConfigMap 热更新、Lease 领导选举与 xihan pack 产物 |
SamplePlugin、EchoPlugin、EchoWasmPlugin、EchoGoPlugin、CacheGoPlugin | 进程内、进程外(.NET、Go)与 Wasm 插件 |
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}'