Skip to content

编写自定义集成 ​

更新: 2026-10-16 15:20:09   字数: 0 字   时长: 0 分钟

当官方集成与 Community Toolkit 都没有覆盖您的资源时,可以自己写一个集成。一个「托管集成」本质上就是:

  1. 一个继承 Resource 的类型(描述资源是什么)。
  2. 一组 IDistributedApplicationBuilder 上的扩展方法(让用户能 Add*** 它)。
  3. 可选:连接字符串支持、发布行为的自定义。

最小可用示例 ​

假设我们要集成一个内部服务,它只需要一个地址和一个 API Key。

1. 定义资源类型 ​

csharp
public sealed class InternalServiceResource(string name)
    : Resource(name), IResourceWithConnectionString
{
    public required ReferenceExpression Endpoint { get; init; }
    public required IResourceBuilder<ParameterResource> ApiKey { get; init; }

    public ReferenceExpression ConnectionStringExpression =>
        ReferenceExpression.Create(
            $"{Endpoint};ApiKey={ApiKey.Resource.ValueExpression}");
}

要点:

  • 构造函数接收 name,并传给基类 Resource。
  • 实现 IResourceWithConnectionString 后,该资源才能被 WithReference 消费。
  • 使用 ReferenceExpression 而不是直接拼字符串,可以让值在运行时解析(例如参数值在部署时才确定)。

2. 提供扩展方法 ​

csharp
public static class InternalServiceResourceBuilderExtensions
{
    public static IResourceBuilder<InternalServiceResource> AddInternalService(
        this IDistributedApplicationBuilder builder,
        [ResourceName] string name,
        IResourceBuilder<ParameterResource>? apiKey = null)
    {
        var key = apiKey ?? builder.AddParameter($"{name}-api-key", secret: true);

        var resource = new InternalServiceResource(name)
        {
            Endpoint = ReferenceExpression.Create($"https://api.internal.example.com"),
            ApiKey = key
        };

        return builder.AddResource(resource)
            .WithInitialState(new CustomResourceSnapshot
            {
                ResourceType = "InternalService",
                State = "Running",
                Properties = [new("Endpoint", "https://api.internal.example.com")]
            });
    }
}

使用时:

csharp
var internalService = builder.AddInternalService("internal-api");

builder.AddProject<Projects.Api>("api")
    .WithReference(internalService);

3. 如果需要本地容器 ​

把上面的扩展方法改成返回容器资源即可复用 Aspire 的容器能力:

csharp
public static IResourceBuilder<InternalServiceResource> AddInternalService(
    this IDistributedApplicationBuilder builder,
    [ResourceName] string name)
{
    return builder.AddContainer(name, "registry.example.com/internal-api:1.2.3")
        .WithHttpEndpoint(targetPort: 8080)
        // ...转换为自定义资源并附加注解
        .WithAnnotation(new InternalServiceAnnotation());
}

让资源在仪表板上显示得更好 ​

初始状态 ​

通过 WithInitialState 提供资源类型、状态与自定义属性,仪表板的资源列表会展示这些信息:

csharp
builder.AddResource(myResource)
    .WithInitialState(new CustomResourceSnapshot
    {
        ResourceType = "MyResource",
        State = "Running",
        Properties =
        [
            new("Region", "cn-east-2"),
            new("Tier", "Standard")
        ],
        Urls = [new("https://myresource.example.com", "https://myresource.example.com")]
    });

健康检查 ​

csharp
builder.AddResource(myResource)
    .WithHealthCheck("myresource-ready");

自定义资源命令 ​

让用户可以在仪表板上对资源执行操作:

csharp
builder.AddResource(myResource)
    .WithCommand("restart", "Restart", async context =>
    {
        // 执行重启逻辑
        return CommandResults.Success();
    });

自定义资源 URL ​

csharp
builder.AddResource(myResource)
    .WithUrl("https://myresource.example.com", "管理控制台");

发布行为的自定义 ​

如果资源需要参与发布(生成部署清单、映射到云服务),可以实现发布相关接口或通过注解描述其发布形态。关键词:

概念用途
PublishAsConnectionString()发布时只输出连接字符串,不进行真正的资源映射。
IPublishingActivityReporter在发布过程中向用户报告进度。
ResourceSnapshot / 注解为发布器提供资源的元数据。

先看看别人怎么写的

社区工具包里有很多体量不大的集成实现。遇到不确定的写法时,直接阅读对应仓库的源码往往比文档更快。

打包与分发 ​

  • 包名建议:自有前缀 + Hosting,例如 Contoso.Aspire.Hosting.InternalService。
  • 目标框架跟随官方集成使用的 TFM(通常与当前 Aspire 主版本一致)。
  • 在 README 中明确写出:支持的 Aspire 版本、资源的本地实现(容器?模拟器?)、以及发布到各平台时的映射行为。

实战建议 ​

  • 本地实现优先:一个有容器实现的自定义集成,比只能连真实服务的集成有用得多。
  • 连接字符串用 ReferenceExpression:避免在构建期就固化值。
  • 参数默认标记 secret: true:只要涉及密钥,默认保密。
  • 不要吞掉异常:资源创建失败时应清晰抛出,Aspire 会把它呈现为 FailedToStart。

下一步 ​

你觉得这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度