自定义资源
更新: 2026-10-16 15:20:09 字数: 0 字 时长: 0 分钟
Aspire 内置了项目、容器、可执行文件等资源类型,集成包又补充了大量常见服务。当这些都覆盖不到时,您可以定义自定义资源。
什么时候需要自定义资源
| 场景 | 说明 |
|---|---|
| 内部平台或自研中间件 | 官方与社区都不会有对应集成。 |
| 需要把「非进程型资源」纳入应用模型 | 例如一个 SaaS 服务、一个外部 API 端点。 |
| 需要自定义仪表板展示与操作 | 自定义资源类型 + 自定义命令 + 自定义 URL。 |
| 需要参与发布流水线 | 让资源在部署时生成特定产物。 |
最小自定义资源
1. 定义资源类型
csharp
using Aspire.Hosting.ApplicationModel;
public sealed class ThirdPartyApiResource(string name) : Resource(name)
{
public required string BaseUrl { get; init; }
}大多数内置资源都继承 Resource 基类;如果资源需要提供连接信息,可以实现 IResourceWithConnectionString。
2. 提供扩展方法
csharp
public static class ThirdPartyApiResourceBuilderExtensions
{
public static IResourceBuilder<ThirdPartyApiResource> AddThirdPartyApi(
this IDistributedApplicationBuilder builder,
[ResourceName] string name,
string baseUrl)
{
var resource = new ThirdPartyApiResource(name) { BaseUrl = baseUrl };
return builder.AddResource(resource)
.WithInitialState(new CustomResourceSnapshot
{
ResourceType = "ThirdPartyApi",
State = "Running",
Properties = [new("BaseUrl", baseUrl)]
});
}
}在 AppHost 中使用:
csharp
var api = builder.AddThirdPartyApi("partner", "https://api.partner.example.com");
builder.AddProject<Projects.Web>("web")
.WithReference(api);[ResourceName] 特性
给 name 参数加上 [ResourceName] 可以让 IDE 在调用处提供校验与提示,官方的 Add* 方法都这样做。
让资源支持引用
如果资源能提供连接信息,实现 IResourceWithConnectionString:
csharp
public sealed class ThirdPartyApiResource(string name)
: Resource(name), IResourceWithConnectionString
{
public required string BaseUrl { get; init; }
public required IResourceBuilder<ParameterResource> ApiKey { get; init; }
public ReferenceExpression ConnectionStringExpression =>
ReferenceExpression.Create($"{BaseUrl};ApiKey={ApiKey.Resource.ValueExpression}");
}用 ReferenceExpression 而不是字符串拼接
参数值可能在部署时才能确定,直接拼接字符串会在构建期就把值固化下来。
仪表板呈现
初始状态与属性
csharp
builder.AddResource(resource)
.WithInitialState(new CustomResourceSnapshot
{
ResourceType = "ThirdPartyApi",
State = "Running",
Properties =
[
new("Region", "cn-east-2"),
new("Tier", "Standard")
],
Urls = [new("https://api.partner.example.com", "合作伙伴控制台")]
});健康检查
csharp
builder.AddResource(resource)
.WithHealthCheck("partner-api-ready");自定义命令
让用户可以在仪表板上对资源执行操作:
csharp
builder.AddResource(resource)
.WithCommand("rotate-key", "轮换密钥", async context =>
{
// 执行轮换逻辑
return CommandResults.Success();
});自定义 URL
csharp
builder.AddResource(resource)
.WithUrl("https://portal.partner.example.com", "合作伙伴门户");参与发布与部署
| 概念 | 用途 |
|---|---|
PublishAsConnectionString() | 发布时只输出连接字符串,不做资源映射。 |
| publishing / deploying 步骤 | 在流水线中插入自定义逻辑。 |
注解(IResourceAnnotation) | 向发布器传递资源元数据。 |
测试自定义资源
自定义资源与注解同样可以被测试覆盖:
csharp
[Fact]
public async Task Custom_Resource_Should_Expose_Expected_Url()
{
var appHost = await DistributedApplicationTestingBuilder
.CreateAsync<Projects.MyApp_AppHost>();
await using var app = await appHost.BuildAsync();
var resource = app.Resources.GetResource("partner");
Assert.NotEmpty(resource.Annotations.OfType<ResourceUrlAnnotation>());
}最佳实践
- 一个注解只做一件事:不要写一个「万能配置注解」。(反面例子:
ConfigAnnotation同时塞进重试策略、日志设置与安全设置。) - 名称要有意义:
DatabaseConnectionPoolAnnotation比DbAnnotation好。 - 遵循构建器模式:扩展方法返回
IResourceBuilder<T>以支持链式调用。 - 提供 XML 文档:注解与扩展方法都应写注释。
- 提供合理默认值,让最简单的调用就能工作。
- 本地实现优先:能提供容器或模拟器实现的自定义资源,价值远高于只能连真实服务的资源。





