ドキュメントAspire を試す
ドキュメント試す

リソース階層

Aspire は、所有、包含、グループ化を表現するために、リソース間の 親子関係 をモデル化できます。

親子関係には、2 つの目的があります:

  • ライフサイクル包含: 子の実行は親に結び付けられ、開始、停止、障害は親から子へ自動的に連鎖します。
  • ダッシュボード可視化: ダッシュボードや可視化で子が親の 下にネスト されて表示され、可読性が向上します。

リソースが IResourceWithParent インターフェイスを実装すると、真の包含 が宣言されます。つまり、そのライフサイクルは親によって制御されます:

  • 起動: 子リソースは、親が起動した後にのみ起動します(ただし準備完了は独立しています)。
  • 停止: 親が停止または削除されると、子も自動的に停止されます。
  • 障害伝播: 親が終端障害状態(FailedToStart など)に入ると、依存する子は停止されます。

視覚的グループ化(ライフサイクルへの影響なし)

Section titled “視覚的グループ化(ライフサイクルへの影響なし)”

Aspire は、リソース構築時に WithParentRelationship() メソッドを使うことで、視覚専用の親子関係 もサポートします。

視覚的関係:

  • ダッシュボード レイアウトのみに 影響します。
  • ライフサイクルには影響しません。リソースは運用上独立しています。
  • 関連コンポーネントを論理的にまとめることで 明確性 を高めます。

手動リレーションシップ — 推論なし

Section titled “手動リレーションシップ — 推論なし”

Aspire は、名前、依存関係、ネットワーク リンクに基づいて親子関係を自動推論 しません

関係は、次のいずれかで 明示的に宣言 する必要があります:

  • IResourceWithParent を実装: ライフサイクル依存と視覚的ネストを作成します。
  • .WithParentRelationship() を使用: 視覚的ネストのみを作成します。

この明示性により、開発者はリソースの包含と表示を完全に制御できます。

次のシナリオは、Aspire が親子関係をどのようにモデル化するかを示しています:

シナリオ
ログ用サイドカーを持つメイン アプリ コンテナーApp コンテナーFluentd コンテナー
管理ダッシュボード付きデータベースDatabase コンテナーAdmin UI コンテナー
関連する正常性モニターを持つマイクロサービスAPI コンテナーHealth probe コンテナー

Aspire では、構成、接続の詳細、分散リソース間の依存関係を 構造化値 でモデル化します。これらの値は、単なる文字列としてではなく関係を明示的に捉えるため、アプリケーション グラフは 可搬性が高く、検査可能で、進化可能 になります。

Aspire は、これらの関係を 異種混在の有向非巡回グラフ(DAG で表現します。このグラフは依存順序だけでなく、構成、接続、実行時動作という複数の抽象レベルで 構造化値 がリソース間をどのように渡るかも追跡します。

C# — AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
var db = builder.AddPostgres("pg");
var api = builder.AddProject("api").WithReference(db);
var web = builder.AddNpmApp("web").WithReference(api);
builder.Build().Run();
architecture-beta

  service db(logos:postgresql)[pg]
  service epr(iconoir:server-connection)[Endpoint Reference]
  service api(logos:dotnet)[api]
  service ctr(iconoir:server-connection)[Connection String Reference]
  service frontend(logos:react)[web]

  db:L <-- R:ctr
  ctr:L <-- R:api
  api:L <-- R:epr
  epr:L <-- R:frontend

通常、リソース参照は非巡回グラフを形成し、循環は許可されません。ただし、エンドポイント参照は特別扱い され、意図的に 循環を形成できる 場合があります。

エンドポイントは 外部エンティティ としてモデル化されます:

  • リソース依存グラフにおける エッジではありません
  • 次のような現実的な相互参照を可能にします:
    • フロントエンド アプリと OIDC サーバーが互いの URL(リダイレクト、ログイン コールバック)を参照する。
    • フロントエンド URL を参照する CORS 設定をバックエンドが公開する。

リソースは次を通じて互いに接続されます:

  • WithReference() 呼び出し: 直接的なリソース間依存。
  • 環境変数と CLI 引数: 構造化参照を含む構成値。
  • その他の構成ソース: 構造化値参照で設定される値。

各参照はグラフに エッジを追加 し、Aspire は次を可能にします:

  • 依存順序の追跡。
  • サービス間での構造化値のクリーンな伝播。
  • 実行前のアプリケーション整合性の検証。

Aspire は、構造化値リテラル値 を区別します。

  • 構造化値 は意味を保持します(例: 「これはサービス URL」対「これは生の文字列」)。
  • リテラル値 は不活性で、モードをまたいでそのまま運ばれます。

公開時と実行時には:

  • 構造化値は、可能であれば 解決 され、またはターゲット成果物(環境変数、引数値など)へ 変換 されます。
  • リテラル値は単純にコピーされます。

Aspire の各構造化値型は、2 つの基本インターフェイスを実装します:

インターフェイス使用タイミング目的
IValueProviderRun modeアプリケーション起動時にライブ値を解決します。
IManifestExpressionProviderPublish mode配置成果物に構造化式({pg.outputs.url} のような)を出力します。

この二重インターフェイス モデルは、遅延評価 を可能にします:

  • publish 中は、構造化プレースホルダーが出力され、実行時値はまだ解決されません。
  • run 中は、構造化参照が URL、ポート、接続文字列などのライブ値へ解決されます。

内部的には、値プロバイダーはアプリケーション グラフ構築中に、環境変数、CLI 引数、構成フィールド、その他の構造化出力へ関連付けられます。

表すものRun ModePublish Mode
stringリテラル文字列値。同じリテラル。同じリテラル。
EndpointReference別リソース上の名前付きエンドポイントへのリンク。具体 URL(http://localhost:5000)。ターゲット固有のエンドポイント変換(DNS、ingress など)。
EndpointReferenceExpressionエンドポイントのプロパティ(Host, Port, Scheme)。具体値。プラットフォーム固有の変換。
ConnectionStringReferenceリソース接続文字列へのシンボリック ポインター。具体文字列。トークンまたは外部化シークレット。
ParameterResource外部入力、シークレット、または設定。ローカル開発値または環境参照。置換用プレースホルダー ${PARAM}
ReferenceExpression参照を埋め込んだ複合文字列。具体的な書式済み文字列。置換用に保持された書式文字列。

ReferenceExpression は、補間文字列の中にエンドポイント、パラメーター、接続文字列などの 構造化値オブジェクト を保持し、安全なタイミングまで評価を遅延させます。

Aspire はモデルを 2 つの明確なモード で評価します:

フェーズReferenceExpression の結果
Publish発行先固有のプレースホルダー テキスト(例: {api.bindings.http.host})。
Runlocalhost などの具体値。

例 — ReferenceExpression の使用:

C# — AppHost.cs
var ep = api.GetEndpoint("http");
builder.WithEnvironment("HEALTH_URL",
ReferenceExpression.Create(
$"https://{ep.Property(EndpointProperty.Host)}:{ep.Property(EndpointProperty.Port)}/health"
)
);

公開マニフェスト抜粋:

HEALTH_URL=https://{api.bindings.http.host}:{api.bindings.http.port}/health

実行時の値:

HEALTH_URL=https://localhost:5000/health

ExecutionContext を使う代替パターン

Section titled “ExecutionContext を使う代替パターン”
C# — AppHost.cs
var ep = api.GetEndpoint("http");
if (builder.ExecutionContext.IsRunMode)
{
builder.WithEnvironment("HEALTH_URL",
$"{ep.Url}/health"); // 具体値
}
else
{
builder.WithEnvironment("HEALTH_URL",
ReferenceExpression.Create($"{ep}/health")); // 構造化値
}

IResourceWithConnectionString で使われるパターン

Section titled “IResourceWithConnectionString で使われるパターン”

一般的な実装では、ReferenceExpression で接続文字列を構築し、値オブジェクト(エンドポイント プロパティ、パラメーター、その他参照)を混在させます:

private static ReferenceExpression BuildConnectionString(
EndpointReference endpoint,
ParameterResource passwordParameter)
{
var host = endpoint.Property(EndpointProperty.IPV4Host);
var port = endpoint.Property(EndpointProperty.Port);
var pwd = passwordParameter;
return ReferenceExpression.Create(
$"Server={host},{port};User ID=sa;Password={pwd};TrustServerCertificate=true");
}

次のパターンは ReferenceExpression 使用時によくある誤りです:

エラー正しいアプローチ
まず文字列を作り、後からラップする。ReferenceExpression.Create(...) 内で 構築する。
publish 中に Endpoint.Url へアクセスする。式内で Endpoint.Property(...) を使う。
解決済み文字列とプレースホルダーを混在させる。値全体を 1 つの ReferenceExpression に入れる。

EndpointReference は、他リソースのエンドポイントとやり取りするための基本型です。次のようなプロパティを提供します:

  • Url: エンドポイントの完全 URL(例: http://localhost:6379)。
  • Host: エンドポイントのホスト名または IP アドレス。
  • Port: エンドポイントのポート番号。

これらのプロパティは、アプリケーションの起動シーケンス中に動的に解決されます。エンドポイント割り当て前にアクセスすると例外になります。

エンドポイントをサポートするリソースは IResourceWithEndpoints を実装し、GetEndpoint(name) を使って EndpointReference を取得できるようにする必要があります。これは組み込みの ProjectResourceContainerResourceExecutableResource に実装されています。これにより、エンドポイントへプログラムからアクセスし、リソース間で受け渡せます。

例 — エンドポイントへのアクセスと解決
var builder = DistributedApplication.CreateBuilder(args);
var redis = builder.AddContainer("redis", "redis")
.WithEndpoint(name: "tcp", targetPort: 6379);
// "tcp" という名前のエンドポイントへの参照を取得
var endpoint = redis.GetEndpoint("tcp");
builder.Build().Run();

エンドポイントは、Aspire が run mode 中に実行時値(HostPortUrl など)を解決すると allocated になります。割り当ては 起動シーケンス の一部として行われ、ローカル開発でエンドポイントを使用できる状態を保証します。

publish mode では、エンドポイントは具体値で割り当てられません。代わりに、値は マニフェスト式 またはバインディング(例: {redis.bindings.tcp.host}:{redis.bindings.tcp.port})として表現され、デプロイ基盤側で解決されます。

コンテキストRun ModePublish Mode
エンドポイント値完全解決(tcp://localhost:6379)。マニフェスト式({redis.bindings.tcp.url})として表現。
ユース ケースローカル開発とデバッグ。デプロイ環境(Kubernetes、Azure、AWS など)。
動作エンドポイントは動的に割り当てられる。エンドポイント プレースホルダーは実行時に解決される。

EndpointReferenceIsAllocated プロパティを使うと、実行時値へアクセスする前に割り当て済みかを確認できます。

割り当て済みエンドポイントへ安全にアクセスする

Section titled “割り当て済みエンドポイントへ安全にアクセスする”

エンドポイント解決は DistributedApplication の起動シーケンス中に行われます。エンドポイント値(UrlHostPort など)へ安全にアクセスするには、割り当て完了まで待つ必要があります。Aspire は AfterEndpointsAllocatedEvent などのイベント API を提供し、割り当て後にエンドポイントへアクセスできます。これにより、エンドポイント準備完了後にのみコードが実行されます。

例 — 割り当て確認とイベント使用
var builder = DistributedApplication.CreateBuilder(args);
// TCP エンドポイントを持つ Redis コンテナーを追加
var redis = builder.AddContainer("redis", "redis")
.WithEndpoint(name: "tcp", targetPort: 6379);
// EndpointReference を取得
var endpoint = redis.GetEndpoint("tcp");
// 割り当て状態を確認し Url へアクセス
Console.WriteLine($"IsAllocated: {endpoint.IsAllocated}");
try
{
Console.WriteLine($"Url: {endpoint.Url}");
}
catch (Exception ex)
{
Console.WriteLine($"Error accessing Url: {ex.Message}");
}
// 解決済みプロパティを得るため AfterEndpointsAllocatedEvent を購読
builder.Eventing.Subscribe<AfterEndpointsAllocatedEvent>(
(@event, cancellationToken) =>
{
Console.WriteLine($"Endpoint allocated: {endpoint.IsAllocated}");
Console.WriteLine($"Resolved Url: {endpoint.Url}");
return Task.CompletedTask;
});
// アプリケーションを起動
builder.Build().Run();

前述のコードは、アプリケーションが run modepublish mode かで異なる結果を出力します:

Run Mode:

Run Mode — コンソール出力
IsAllocated: True
Resolved Url: http://localhost:6379

Publish Mode:

Publish Mode — コンソール出力
IsAllocated: False
Error accessing Url: Endpoint has not been allocated.

他リソースからのエンドポイント参照

Section titled “他リソースからのエンドポイント参照”

このセクションでは、Aspire で他リソースのエンドポイントを参照し、依存関係と構成を効果的に接続する方法を説明します。

WithReference API を使うと、エンドポイント参照をターゲット リソースへ直接渡せます。

C# — AppHost.cs
var builder = DistributedApplication.CreateBuilder(args);
var redis = builder.AddContainer("redis", "redis")
.WithEndpoint(name: "tcp", targetPort: 6379);
builder.AddProject<Projects.Worker>("worker")
.WithReference(redis.GetEndpoint("tcp"));
builder.Build().Run();

WithReference は、サービス検知を使うアプリケーション向けに最適化されています。

WithEnvironment API は、エンドポイント詳細を環境変数として公開し、実行時構成を可能にします。

例 — 環境変数として Redis エンドポイントを渡す
var builder = DistributedApplication.CreateBuilder(args);
var redis = builder.AddContainer("redis", "redis")
.WithEndpoint(name: "tcp", targetPort: 6379);
builder.AddProject<Worker>("worker")
.WithEnvironment("RedisUrl", redis.GetEndpoint("tcp"));
builder.Build().Run();

WithEnvironment は、ターゲット リソースに注入する構成名を完全に制御できます。

EndpointReferenceExpression — エンドポイント要素へのアクセス

Section titled “EndpointReferenceExpression — エンドポイント要素へのアクセス”

EndpointReferenceExpression は、エンドポイントの 1 つのフィールドHostPortScheme など)を表します。 C# では endpoint.Property(...) を呼び出してそのフィールドを取得します。TypeScript AppHost では await endpoint.property(...) を呼び出します。結果は引き続き構造化値であり、publish/run 時まで遅延されます。

必要なものパターン
1 つの要素のみ(例: host)C#: endpoint.Property(EndpointProperty.Host)
TypeScript: await endpoint.property(EndpointProperty.Host)
複数要素を 1 つの設定へ合成するReferenceExpression を構築する(専用セクションを参照)。
TypeScript — apphost.ts
import { createBuilder, EndpointProperty } from './.modules/aspire.js';
const builder = await createBuilder();
const redis = await builder.addContainer('redis', 'redis');
await redis.withEndpoint({ name: 'tcp', targetPort: 6379 });
const ep = await redis.getEndpoint('tcp');
const redisHost = await ep.property(EndpointProperty.Host);
const redisPort = await ep.property(EndpointProperty.Port);
await builder
.addProject('worker', '../Worker/Worker.csproj')
.withEnvironment('REDIS_HOST', redisHost)
.withEnvironment('REDIS_PORT', redisPort);
await builder.build().run();

このパターンでは、エンドポイント プロパティ呼び出しは EndpointReferenceExpression を返し、これは実行時に解決される構造化値です。

例 — 完全な Redis URL を構築
var ep = redis.GetEndpoint("tcp");
builder.WithEnvironment("REDIS_URL",
ReferenceExpression.Create(
$"redis://{ep.Property(EndpointProperty.HostAndPort)}"
)
);

このパターンはエンドポイント値の早期解決を避け、publish mode と run mode の両方で機能します。

プロパティ意味
Url完全修飾 URL(scheme://host:port)。
Host or IPV4Hostホスト名または IPv4 リテラル。
Port or TargetPort割り当て済みホスト ポートとコンテナー内ポート。
Schemehttptcp など。
HostAndPort便利な複合値(host:port)。

EndpointReference 型は、エンドポイントのライブ値またはプレースホルダー値を公開し、.Property(...)EndpointReferenceExpression を作成できます。

主要メンバー:

メンバー説明
Url, Host, Port, Scheme, TargetPortrun mode では具体値、publish mode では未定義。
bool IsAllocated具体値が利用可能か(run mode)を示す。
EndpointReferenceExpression Property(EndpointProperty)1 つのフィールドに対する遅延式を作成する。

EndpointReferenceExpression は同じ IManifestExpressionProvider / IValueProvider の組を実装しているため、ReferenceExpression に埋め込むことも、GetValueAsync() で直接解決することもできます。

コンテキスト ベースのエンドポイント解決

Section titled “コンテキスト ベースのエンドポイント解決”

Aspire は、ソース リソースとターゲット リソースの関係に応じてエンドポイントを異なる方法で解決します。これにより、すべての環境で適切な通信が保証されます。

SourceTargetResolutionExample URL
ContainerContainerContainer network (resource name:port).redis:6379
Executable / ProjectContainerHost network (localhost:port).localhost:6379
ContainerExecutable / ProjectHost network (host.docker.internal:port).host.docker.internal:5000

高度なシナリオ: 既定のエンドポイント解決の上書き

Section titled “高度なシナリオ: 既定のエンドポイント解決の上書き”

Aspire は、実行コンテキスト(run mode と publish mode、コンテナーと実行可能ファイルなど)に基づいてエンドポイントを異なる方法で解決します。場合によっては、既定とは異なる視点でエンドポイントを取得するために、この解決動作を上書きする必要があります。

たとえば、ある project リソースが Grafana と Keycloak コンテナーを構成する必要があるケースを考えてみます。この project 自体は通常ホスト ベース URL を受け取りますが、これらのサービス同士を通信させるために、コンテナー間 URL を提供する必要があります。

ValueProviderContext を使った明示的なコンテキスト解決

Section titled “ValueProviderContext を使った明示的なコンテキスト解決”

Aspire 13.2 以降では、ValueProviderContext を使用してエンドポイント解決コンテキストを明示的に制御できます。これにより、特定リソースやネットワークの視点で解決したい場合に、URL を手動構築するよりもクリーンな代替手段になります。

特定リソース(Caller)から解決する

Section titled “特定リソース(Caller)から解決する”

Caller プロパティを使うと、特定の呼び出し元リソースの視点でエンドポイントを解決できます:

C# — リソース視点でエンドポイントを解決
var builder = DistributedApplication.CreateBuilder(args);
var redis = builder.AddRedis("cache");
var containerApp = builder.AddContainer("worker", "myimage");
// エンドポイント参照を取得
var endpoint = redis.GetEndpoint("tcp");
// コンテナー視点で URL を解決
var url = await endpoint.GetValueAsync(new ValueProviderContext {
Caller = containerApp.Resource,
});
// URL はコンテナー間通信に適したものになる
// 例: リソース名をホスト名として使う "cache:6379"

これは、異なるコンテキスト(コンテナーとホスト プロセス)で実行される可能性があるリソース間で接続情報を渡す必要がある場合に特に有用です。

特定ネットワークから解決する

Section titled “特定ネットワークから解決する”

Network プロパティを使うと、特定ネットワークの視点でエンドポイントを解決できます:

C# — ネットワーク視点でエンドポイントを解決
var builder = DistributedApplication.CreateBuilder(args);
var redis = builder.AddRedis("cache");
// エンドポイント参照を取得
var endpoint = redis.GetEndpoint("tcp");
// 既定の Aspire コンテナー ネットワーク向け URL を解決
var url = await endpoint.GetValueAsync(new ValueProviderContext {
Network = KnownNetworkIdentifiers.DefaultAspireContainerNetwork
});
// URL はコンテナー ネットワークに適したものになる
// 例: リソース名をホスト名として使う "cache:6379"

KnownNetworkIdentifiers クラスは、事前定義済みネットワーク識別子を提供します:

  • LocalhostNetwork: localhost ベース URL に解決
  • DefaultAspireContainerNetwork: リソース名を使うコンテナー ネットワーク URL に解決
  • PublicInternet: 外部アクセス可能な URL に解決

次のコードは、Grafana や Keycloak など他リソースと通信する必要がある project に対して環境変数を設定する方法を示します。URL が実行コンテキスト(run mode と publish mode)に応じて正しく解決されることを保証します。

Aspire 13.2 では、ValueProviderContext を使ってこれを簡素化できます:

C# — ValueProviderContext で簡素化(Aspire 13.2+)
var builder = DistributedApplication.CreateBuilder(args);
var keycloak = builder.AddKeycloak("keycloak", 8080);
var grafana = builder.AddContainer("grafana", "grafana/grafana");
var api = builder.AddProject<Projects.Api>("api")
.WithEnvironment(async ctx =>
{
var keyCloakEndpoint = keycloak.GetEndpoint("http");
var grafanaEndpoint = grafana.GetEndpoint("http");
ctx.EnvironmentVariables["Grafana__Url"] = grafanaEndpoint;
if (ctx.ExecutionContext.IsRunMode)
{
// コンテナー ネットワーク視点で解決
var keycloakUrl = await keyCloakEndpoint.GetValueAsync(new ValueProviderContext
{
Network = KnownNetworkIdentifiers.DefaultAspireContainerNetwork
});
ctx.EnvironmentVariables["Keycloak__AuthServerUrl"] = keycloakUrl;
}
else
{
// publish mode ではエンドポイント リゾルバーに URL 処理を任せる
ctx.EnvironmentVariables["Keycloak__AuthServerUrl"] = keyCloakEndpoint;
}
});
builder.Build().Run();

Aspire 13.2 より前 では、URL を手動で構築する必要がありました:

C# — URL の手動構築(pre-13.2)
var builder = DistributedApplication.CreateBuilder(args);
var keycloak = builder.AddKeycloak("keycloak", 8080);
var grafana = builder.AddContainer("grafana", "grafana/grafana");
var api = builder.AddProject<Projects.Api>("api")
.WithEnvironment(ctx =>
{
var keyCloakEndpoint = keycloak.GetEndpoint("http");
var grafanaEndpoint = grafana.GetEndpoint("http");
ctx.EnvironmentVariables["Grafana__Url"] = grafanaEndpoint;
if (ctx.ExecutionContext.IsRunMode)
{
// pre-13.2 では URL の手動構築が必要
var keycloakUrl = new UriBuilder(keyCloakEndpoint.Url)
{
Host = keycloak.Resource.Name,
Port = keyCloakEndpoint.TargetPort ?? keyCloakEndpoint.Port,
};
ctx.EnvironmentVariables["Keycloak__AuthServerUrl"] = keycloakUrl.ToString();
}
else
{
// publish mode ではエンドポイント リゾルバーに URL 処理を任せる
ctx.EnvironmentVariables["Keycloak__AuthServerUrl"] = keyCloakEndpoint;
}
});
builder.Build().Run();