dotnet-aspire-patterns について
dotnet-aspire-patterns は、分散アプリケーションを開発する人向けの .NET Aspire スキルです。AppHostによるオーケストレーション、サービスディスカバリー、バックエンドサービス用コンポーネント、ローカルの可観測性、ヘルスチェックを扱い、開発時の実行管理と本番デプロイを区別します。
主な機能
- 01AppHostのトポロジーとリソースのライフサイクル
- 02サービスディスカバリーと接続文字列
- 03データベース、キャッシュ、メッセージブローカー用コンポーネント
- 04ヘルスチェックとテレメトリーのServiceDefaults
- 05ログ、トレース、メトリクスを表示するローカルダッシュボード
- 06Aspireと手動オーケストレーションの選択指針
活用シーン
- 01複数の.NETサービスとバックエンド基盤の接続
- 02リソースのヘルス状態に応じた起動順序の設定
- 03サービスプロジェクト間での可観測性の標準化
- 04ローカルオーケストレーション方式の検討
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ wshaddix/ dotnet-skills --skill dotnet-aspire-patternsインストール後、Claude Code で/dotnet-aspire-patternsを入力して読み込まれたか確認します。
詳細
dotnet-aspire-patterns
クラウド対応の分散アプリケーションを構築するための .NET Aspire オーケストレーションパターンです。AppHost の構成、サービスディスカバリー、バックエンドサービス(データベース、キャッシュ、メッセージブローカー)を統合するためのコンポーネントモデル、ローカルでの可観測性を実現する Aspire ダッシュボード、分散ヘルスチェック、Aspire と手動のコンテナーオーケストレーションのどちらを選ぶべきかについて説明します。
対象外: Dockerfile の記述とマルチステージビルドについては、[skill:dotnet-containers] を参照してください。Kubernetes マニフェスト、Helm チャート、Docker Compose については、[skill:dotnet-container-deployment] を参照してください。OpenTelemetry SDK の構成とカスタムメトリクスについては、[skill:dotnet-observability] を参照してください。DI サービスのライフタイムの仕組みについては、[skill:dotnet-csharp-dependency-injection] を参照してください。バックグラウンドサービスのホスティングについては、[skill:dotnet-background-services] を参照してください。
相互参照:[skill:dotnet-containers] ではコンテナーイメージの最適化とベースイメージの選択、[skill:dotnet-container-deployment] では Kubernetes/Compose を使った本番環境へのデプロイ、[skill:dotnet-observability] では Aspire の既定値を超える OpenTelemetry の詳細、[skill:dotnet-csharp-dependency-injection] では DI の基礎、[skill:dotnet-background-services] ではホステッドサービスのライフサイクルパターンを説明しています。
Aspire の概要
.NET Aspire は、可観測性を備えた本番環境対応の分散アプリケーションを構築するための、明確な方針を持つスタックです。次の機能を提供します。
- オーケストレーション -- 分散トポロジーを C#(AppHost)で定義します
- コンポーネント -- 一般的なバックエンドサービス向けに事前構成された NuGet パッケージ
- サービスの既定値 -- OpenTelemetry、ヘルスチェック、レジリエンスの共有構成
- ダッシュボード -- トレース、ログ、メトリクス、リソースの状態を確認できるローカル開発用 UI
Aspire はデプロイ先ではありません。ローカルでの開発およびテスト体験をオーケストレーションします。本番環境向けには、デプロイツール(Azure Developer CLI、Kubernetes など)が使用するマニフェストを生成します。
Aspire を使用する場面
| シナリオ | 推奨事項 |
|---|---|
| 複数の .NET サービスとバックエンドインフラストラクチャ | Aspire AppHost -- ローカル開発とサービスの接続を簡素化します |
| データベースを備えた単一の API | 任意 -- トポロジーがシンプルな場合、Aspire の導入によってオーバーヘッドが増える可能性があります |
| .NET 以外のサービスのみ(Node、Python) | Aspire からコンテナーイメージを参照できますが、ツールの利点は小さくなります |
| ローカル開発で Kubernetes/Compose をすでに使用している | 移行コストを評価してください。Aspire は開発シナリオで docker-compose を置き換えます |
| チームで一貫した可観測性の既定値が必要 | Aspire ServiceDefaults によって、すべてのプロジェクトの OTel を標準化できます |
AppHost の構成
AppHost は、分散アプリケーションのトポロジーを定義する .NET プロジェクト(Aspire.Hosting.AppHost SDK)です。他のプロジェクトやバックエンドサービスを参照し、サービスディスカバリーによってそれらを接続します。
AppHost プロジェクトのセットアップ
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.1.*" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<IsAspireHost>true</IsAspireHost>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.1.*" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.1.*" />
<PackageReference Include="Aspire.Hosting.Redis" Version="9.1.*" />
<PackageReference Include="Aspire.Hosting.RabbitMQ" Version="9.1.*" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MyApi\MyApi.csproj" />
<ProjectReference Include="..\MyWorker\MyWorker.csproj" />
</ItemGroup>
</Project>
トポロジーの定義
var builder = DistributedApplication.CreateBuilder(args);
// Backing services -- Aspire manages containers automatically
var postgres = builder.AddPostgres("pg")
.WithPgAdmin() // Adds pgAdmin UI container
.AddDatabase("ordersdb");
var redis = builder.AddRedis("cache")
.WithRedisCommander(); // Adds Redis Commander UI
var rabbitmq = builder.AddRabbitMQ("messaging")
.WithManagementPlugin(); // Adds RabbitMQ management UI
// Application projects -- wired with service discovery
var api = builder.AddProject<Projects.MyApi>("api")
.WithReference(postgres)
.WithReference(redis)
.WithReference(rabbitmq)
.WithExternalHttpEndpoints(); // Marks endpoints as public in deployment manifests
builder.AddProject<Projects.MyWorker>("worker")
.WithReference(postgres)
.WithReference(rabbitmq)
.WaitFor(api); // Start worker after API is healthy
builder.Build().Run();
リソースのライフサイクル
WaitFor は起動順序を制御します。依存関係から正常であることが報告されるまで、リソースは起動を待機します。
// Worker waits for both the database and API to be ready
builder.AddProject<Projects.MyWorker>("worker")
.WithReference(postgres)
.WaitFor(postgres) // Wait for database container health check
.WaitFor(api); // Wait for API health endpoint
WaitFor がない場合、リソースは並行して起動します。起動順序が重要な場合(たとえば、データベーススキーマが存在している必要があるワーカー)にのみ使用してください。
サービスディスカバリー
Aspire はサービスディスカバリーを自動的に構成し、ハードコードされた URL ではなくリソース名でプロジェクト同士を解決できるようにします。
仕組み
- AppHost は、エンドポイント情報を環境変数と構成として注入します
Aspire.ServiceDefaultsプロジェクトがMicrosoft.Extensions.ServiceDiscoveryを構成します- アプリケーションコードは、
HttpClientまたは接続文字列を介してサービス名でサービスを解決します
検出されたサービスの使用
// In MyApi/Program.cs
var builder = WebApplication.CreateBuilder(args);
// AddServiceDefaults registers service discovery, OpenTelemetry, health checks
builder.AddServiceDefaults();
// HttpClient resolves "worker" via service discovery
builder.Services.AddHttpClient("worker-client", client =>
{
client.BaseAddress = new Uri("https+http://worker");
});
https+http:// スキームプレフィックスは、サービスディスカバリープロバイダーに HTTPS を優先して試し、失敗した場合は HTTP にフォールバックするよう指示します。これは、Aspire でサービス間通信を行う際に推奨されるパターンです。
接続文字列
データベースやキャッシュなどのバックエンドサービスでは、Aspire は標準の ConnectionStrings 構成セクションを介して接続文字列を注入します。
// AppHost: .WithReference(postgres) on the API project
// injects ConnectionStrings__ordersdb automatically
// In MyApi/Program.cs
builder.AddNpgsqlDbContext<OrdersDbContext>("ordersdb");
// Resolves ConnectionStrings:ordersdb from configuration
コンポーネントモデル
Aspire コンポーネントは、バックエンドサービス向けに事前構成されたクライアント統合を提供する NuGet パッケージです。接続管理、ヘルスチェック、テレメトリ、回復性を処理します。
ホスティングパッケージとクライアントパッケージ
| パッケージの種類 | インストール先 | 目的 |
|---|---|---|
Aspire.Hosting.* | AppHost プロジェクト | リソース(コンテナー、接続)を定義して構成する |
Aspire.* (client) | サービスプロジェクト | ヘルスチェックとテレメトリを使用してリソースを利用する |
<PackageReference Include="Aspire.Hosting.PostgreSQL" Version="9.1.*" />
<PackageReference Include="Aspire.Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.1.*" />
一般的なコンポーネント
| コンポーネント | ホスティングパッケージ | クライアントパッケージ |
|---|---|---|
| PostgreSQL(EF Core) | Aspire.Hosting.PostgreSQL | Aspire.Npgsql.EntityFrameworkCore.PostgreSQL |
| PostgreSQL(Npgsql) | Aspire.Hosting.PostgreSQL | Aspire.Npgsql |
| Redis(キャッシュ) | Aspire.Hosting.Redis | Aspire.StackExchange.Redis |
| Redis(出力キャッシュ) | Aspire.Hosting.Redis | Aspire.StackExchange.Redis.OutputCaching |
| RabbitMQ | Aspire.Hosting.RabbitMQ | Aspire.RabbitMQ.Client |
| Azure Service Bus | Aspire.Hosting.Azure.ServiceBus | Aspire.Azure.Messaging.ServiceBus |
| SQL Server(EF Core) | Aspire.Hosting.SqlServer | Aspire.Microsoft.EntityFrameworkCore.SqlServer |
| MongoDB | Aspire.Hosting.MongoDB | Aspire.MongoDB.Driver |
クライアントの登録
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// Each Add* method registers the client, health check, and telemetry
builder.AddNpgsqlDbContext<OrdersDbContext>("ordersdb");
builder.AddRedisClient("cache");
builder.AddRabbitMQClient("messaging");
コンポーネントの Add* メソッドは、次の処理を行います。
- DI にクライアント/DbContext を登録する
- リソースのヘルスチェックを追加する
- クライアントの OpenTelemetry インストルメンテーションを構成する
- 既定の回復性設定(再試行、タイムアウト)を適用する
サービスの既定値
ServiceDefaults プロジェクトは、すべてのサービスプロジェクトから参照される共有ライブラリです。横断的な関心事を標準化します。
ServiceDefaults が構成する内容
public static class Extensions
{
public static IHostApplicationBuilder AddServiceDefaults(
this IHostApplicationBuilder builder)
{
// Service discovery
builder.ConfigureOpenTelemetry();
builder.AddDefaultHealthChecks();
builder.Services.AddServiceDiscovery();
// Resilience for HttpClient
builder.Services.ConfigureHttpClientDefaults(http =>
{
http.AddStandardResilienceHandler();
http.AddServiceDiscovery();
});
return builder;
}
public static IHostApplicationBuilder ConfigureOpenTelemetry(
this IHostApplicationBuilder builder)
{
builder.Logging.AddOpenTelemetry(logging =>
{
logging.IncludeFormattedMessage = true;
logging.IncludeScopes = true;
});
builder.Services.AddOpenTelemetry()
.WithMetrics(metrics => metrics
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation())
.WithTracing(tracing => tracing
.AddAspNetCoreInstrumentation()
.AddGrpcClientInstrumentation()
.AddHttpClientInstrumentation());
builder.AddOpenTelemetryExporters();
return builder;
}
public static IHostApplicationBuilder AddDefaultHealthChecks(
this IHostApplicationBuilder builder)
{
builder.Services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy());
return builder;
}
public static WebApplication MapDefaultEndpoints(
this WebApplication app)
{
app.MapHealthChecks("/health");
app.MapHealthChecks("/alive", new HealthCheckOptions
{
Predicate = r => r.Tags.Contains("live")
});
return app;
}
}
ServiceDefaults の使用
すべてのサービスプロジェクトで ServiceDefaults プロジェクトを参照し、拡張メソッドを呼び出します。
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
// ... service-specific registrations
var app = builder.Build();
app.MapDefaultEndpoints();
// ... middleware and endpoints
app.Run();
ダッシュボード
Aspire ダッシュボードは、AppHost とともに自動的に起動するローカルの可観測性 UI です。次の項目が表示されます。
- リソース -- すべてのプロジェクト、コンテナー、実行可能ファイルの状態
- コンソールログ -- すべてのリソースから集約された stdout/stderr
- 構造化ログ -- 構造化プロパティを含む OpenTelemetry ログレコード
- トレース -- すべてのサービスにまたがる分散トレース
- メトリクス -- リアルタイムのメトリクスチャート
ダッシュボードへのアクセス
AppHost(dotnet run --project MyApp.AppHost)を実行すると、ダッシュボードの URL がコンソールに表示されます。
info: Aspire.Hosting.DistributedApplication[0]
Login to the dashboard at https://localhost:17043/login?t=<token>
Aspire を使用しないプロジェクトでのダッシュボード
Aspire スタック全体を使用しないプロジェクト向けに、ダッシュボードをスタンドアロンコンテナーとして利用できます。
docker run --rm -it -p 18888:18888 -p 4317:18889 \
-d --name aspire-dashboard \
mcr.microsoft.com/dotnet/aspire-dashboard:9.1
アプリを構成して OTLP テレメトリを http://localhost:4317 にエクスポートし、http://localhost:18888 で表示します。
ヘルスチェックと分散トレーシング
コンポーネントのヘルスチェック
各 Aspire コンポーネントは、ヘルスチェックを自動的に登録します。AppHost はこれを使用して、リソースの準備状況を判断します。
// In AppHost -- WaitFor uses health checks to gate startup
builder.AddProject<Projects.MyApi>("api")
.WithReference(postgres)
.WaitFor(postgres); // Waits for Npgsql health check to pass
カスタムヘルスチェック
Aspire の既定のヘルスチェックとともに、アプリケーション固有のヘルスチェックを追加します。
builder.Services.AddHealthChecks()
.AddCheck<OrderProcessingHealthCheck>(
"order-processing",
tags: ["ready"]);
ヘルスチェックのパターン(ライブネスとレディネス、カスタムチェック、ヘルスチェックの公開)の詳細については、[skill:dotnet-observability] を参照してください。
分散トレーシングの統合
Aspire は ServiceDefaults を通じて OpenTelemetry トレーシングを構成します。トレースは HTTP 境界を越えて自動的に伝播します。カスタムスパンを使用する場合は、次のようにします。
private static readonly ActivitySource s_activitySource = new("MyApp.Orders");
public async Task<Order> ProcessOrderAsync(CreateOrderRequest request, CancellationToken ct)
{
using var activity = s_activitySource.StartActivity("ProcessOrder");
activity?.SetTag("order.customer_id", request.CustomerId);
// Calls to other Aspire services carry trace context automatically
var inventory = await _httpClient.GetFromJsonAsync<InventoryResponse>(
$"https+http://inventory-api/api/stock/{request.ProductId}", ct);
// ... process order
return order;
}
分散トレーシングの包括的なガイダンス(カスタム ActivitySource、トレースコンテキストの伝播、スパンイベント)については、[skill:dotnet-observability] を参照してください。
コンテナーリソース
コンテナーイメージの追加
Aspire コンポーネントとして利用できないサービスには、任意のコンテナーイメージを追加します。
var seq = builder.AddContainer("seq", "datalust/seq")
.WithHttpEndpoint(port: 5341, targetPort: 80)
.WithEnvironment("ACCEPT_EULA", "Y");
// Reference the container from a project
builder.AddProject<Projects.MyApi>("api")
.WithReference(seq);
永続ボリューム
既定では、Aspire コンテナーは一時ストレージを使用します。再起動後もデータを保持するには、ボリュームを追加します。
var postgres = builder.AddPostgres("pg")
.WithDataVolume("pg-data") // Named volume for data persistence
.AddDatabase("ordersdb");
外部リソース
Aspire が管理していない既存のインフラストラクチャを参照します。
// Connection string from configuration (not an Aspire-managed container)
var existingDb = builder.AddConnectionString("legacydb");
builder.AddProject<Projects.MyApi>("api")
.WithReference(existingDb);
Aspire と手動のコンテナーオーケストレーションの比較
| 項目 | Aspire | Docker Compose / 手動 |
|---|---|---|
| 構成言語 | C#(厳密な型付け) | YAML |
| サービスディスカバリー | 自動(環境変数の注入) | 手動での DNS/環境変数の構成 |
| ヘルスチェック | コンポーネントごとに自動 | サービスごとに手動で HEALTHCHECK を設定 |
| 可観測性 | OTel とダッシュボードを事前構成 | OTel コレクターを手動でセットアップ |
| IDE との統合 | ホットリロード、F5 デバッグ | デバッガーを手動でアタッチ |
| 本番環境へのデプロイ | マニフェストを生成(AZD、K8s) | マニフェストを直接作成 |
| .NET 以外のサービス | コンテナー参照(統合度は低め) | すべての言語を同等にサポート |
| 学習曲線 | .NET 固有の抽象化 | 業界標準のツール |
スタックの大部分が .NET で、標準化された可観測性、サービスディスカバリー、簡素化されたローカル開発環境を求める場合は Aspire を選択してください。きめ細かな制御や多言語サービスが必要な場合、またはチームがすでに Compose/Kubernetes に習熟している場合は、手動のオーケストレーションを選択してください。
主な原則
- AppHost は開発時のみ使用します -- ローカル開発をオーケストレーションするものであり、本番環境へのデプロイには使用しません
- 生の接続文字列よりコンポーネントを使用します -- コンポーネントにより、ヘルスチェック、テレメトリ、回復性が自動的に追加されます
- ServiceDefaults は必須です -- 一貫した可観測性を実現するため、すべての Aspire サービスプロジェクトで参照する必要があります
- 起動順序の制御には WaitFor を使用します -- 実際の依存関係(スキーマの移行、シードデータなど)に使用し、すべてのリソースには使用しないでください
- OTel の構成を重複させないでください -- Aspire ServiceDefaults が OpenTelemetry を構成します。手動で構成すると、データが二重に収集されます
エージェント利用時の注意点
- Aspire サービスプロジェクトで OpenTelemetry を手動構成しないでください -- ServiceDefaults が OTel プロバイダーをすでに登録しています。手動で
.AddOpenTelemetry()を呼び出すと、トレースやメトリクスが重複して収集され、テレメトリのコストが増大します。 - Aspire サービスプロジェクトで接続文字列をハードコードしないでください --
builder.AddNpgsqlDbContext<T>("name")またはbuilder.Configuration.GetConnectionString("name")を使用してください。Aspire は環境変数を通じて接続文字列を注入するため、値をハードコードするとサービスディスカバリーが迂回されます。 - すべてのリソースに
WaitForを使用しないでください -- 起動が直列化され、起動時間が長くなります。サービスが依存先なしでは実際に起動できない場合(起動時のデータベース移行など)にのみ使用してください。 - サービスプロジェクトから
Aspire.Hosting.*パッケージを参照しないでください -- ホスティングパッケージは AppHost のみに含めます。サービスプロジェクトではクライアントパッケージ(Aspire.Npgsql、Aspire.StackExchange.Redisなど)を使用します。 - AppHost を本番環境のホストと混同しないでください -- AppHost はローカル(または CI)で実行し、リソースをオーケストレーションします。本番環境へのデプロイには、生成したマニフェストまたはインフラストラクチャをコードで管理する方法を使用します。
- 新しいサービスプロジェクトで
AddServiceDefaults()を省略しないでください -- これがないと、サービスディスカバリー、ヘルスチェック、テレメトリが利用できず、Aspire との統合が警告なしに機能しなくなります。
前提条件
- .NET 10 SDK(または Aspire ワークロードを使用した .NET 8/9)
- Docker Desktop または Podman(コンテナーリソース用)
- Aspire ワークロード:
dotnet workload install aspire