配置ツール ビルダーのマニフェスト形式を .NET.NET Aspire する
この記事では、.NET.NET Aspire マニフェスト形式について説明します。 この記事は、デプロイ ツール ビルダーのリファレンス ガイドとして機能し、オンプレミスでもクラウドでも、特定のホスティング プラットフォームに .NET.NET Aspire プロジェクトをデプロイするためのツールの作成に役立ちます。
.NET .NET Aspire は、アプリケーション統合間の相互依存関係の管理を支援することで、ローカル開発エクスペリエンスの を簡略化します。 アプリケーションの配置を簡略化するために、.NET Aspire プロジェクトでは、JSON 形式のファイルとして定義されているすべてのリソースのマニフェストを生成できます。
マニフェストを生成する
マニフェストを生成するには、有効な .NET.NET Aspire プロジェクトが必要です。 開始するには、.NET.NET Aspire テンプレートを使用して aspire-starter
.NET プロジェクトを作成します。
dotnet new aspire-starter --use-redis-cache `
-o AspireApp && `
cd AspireApp
マニフェストの生成は、特別なターゲットで dotnet build
を実行することによって実現されます。
dotnet run --project AspireApp.AppHost\AspireApp.AppHost.csproj `
--publisher manifest `
--output-path ../aspire-manifest.json
先端
--output-path
は相対パスをサポートしています。 前のコマンドでは、../aspire-manifest.json
を使用して、マニフェスト ファイルをプロジェクト ディレクトリのルートに配置します。
詳細については、「dotnet runを
Building...
info: Aspire.Hosting.Publishing.ManifestPublisher[0]
Published manifest to: .\AspireApp.AppHost\aspire-manifest.json
生成されるファイルは .NET.NET Aspire マニフェストであり、ターゲット クラウド環境へのデプロイをサポートするためにツールによって使用されます。
手記
起動プロファイルの一部としてマニフェストを生成することもできます。 launchSettings 次のことを考えてみましょう。json:
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"generate-manifest": {
"commandName": "Project",
"launchBrowser": false,
"dotnetRunMessages": true,
"commandLineArgs": "--publisher manifest --output-path aspire-manifest.json"
}
}
}
基本的なマニフェスト形式
.NET Aspire の既定のスターター テンプレートからマニフェストを発行すると、次の JSON 出力が生成されます。
{
"resources": {
"cache": {
"type": "container.v0",
"connectionString": "{cache.bindings.tcp.host}:{cache.bindings.tcp.port}",
"image": "redis:7.2.4",
"bindings": {
"tcp": {
"scheme": "tcp",
"protocol": "tcp",
"transport": "tcp",
"containerPort": 6379
}
}
},
"apiservice": {
"type": "project.v0",
"path": "../AspireApp.ApiService/AspireApp.ApiService.csproj",
"env": {
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true",
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true"
},
"bindings": {
"http": {
"scheme": "http",
"protocol": "tcp",
"transport": "http"
},
"https": {
"scheme": "https",
"protocol": "tcp",
"transport": "http"
}
}
},
"webfrontend": {
"type": "project.v0",
"path": "../AspireApp.Web/AspireApp.Web.csproj",
"env": {
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true",
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true",
"ConnectionStrings__cache": "{cache.connectionString}",
"services__apiservice__0": "{apiservice.bindings.http.url}",
"services__apiservice__1": "{apiservice.bindings.https.url}"
},
"bindings": {
"http": {
"scheme": "http",
"protocol": "tcp",
"transport": "http"
},
"https": {
"scheme": "https",
"protocol": "tcp",
"transport": "http"
}
}
}
}
}
マニフェスト形式 JSON は、resources
で指定された各リソースのプロパティを含む Program.csと呼ばれる 1 つのオブジェクトで構成されます (各名前の name
引数は、JSON内の各子リソース オブジェクトのプロパティとして使用されます)。
接続文字列とバインド参照
前の例では、2 つのプロジェクト リソースと 1 つの Redis キャッシュ リソースがあります。 webfrontend は、apiservice (プロジェクト) リソースと キャッシュ (Redis) リソースの両方に依存します。
この依存関係は、Webfrontend の環境変数に、他の 2 つのリソースを参照するプレースホルダーが含まれているためにわかっています。
"env": {
// ... other environment variables omitted for clarity
"ConnectionStrings__cache": "{cache.connectionString}",
"services__apiservice__0": "{apiservice.bindings.http.url}",
"services__apiservice__1": "{apiservice.bindings.https.url}"
},
apiservice
リソースは、アプリ ホスト webfrontend
ファイル内の呼び出し WithReference(apiservice)
を使用して Program.cs によって参照され、redis
は呼び出し WithReference(cache)
を使用して参照されます。
var builder = DistributedApplication.CreateBuilder(args);
var cache = builder.AddRedis("cache");
var apiService = builder.AddProject<Projects.AspireApp_ApiService>("apiservice");
builder.AddProject<Projects.AspireApp_Web>("webfrontend")
.WithReference(cache)
.WithReference(apiService);
builder.Build().Run();
プロジェクト リソースの種類間の参照により、サービス検出 変数が参照元プロジェクトに挿入されます。 Redis などの既知の参照型への参照により、接続文字列が挿入されます。
アプリ モデル内のリソースとその間の参照のしくみの詳細については、「オーケストレーションの概要 .NET.NET Aspireを参照してください。
プレースホルダー文字列の構造
プレースホルダー文字列は、.NET.NET Aspire マニフェストの構造を参照します。
プレースホルダー文字列 (この場合url
) の最後のセグメントは、マニフェストを処理するツールによって生成されます。 プレースホルダー文字列で使用できるサフィックスがいくつかあります。
-
connectionString
: Redisなどの既知のリソースの種類。 デプロイ ツールは、ターゲット クラウド環境に最適なインフラストラクチャ内のリソースを変換し、使用するアプリケーションで使用する .NET.NET Aspire 互換性のある接続文字列を生成します。container.v0
リソースでは、connectionString
フィールドが存在し、明示的に指定できます。 これは、コンテナー リソースの種類が WithReference 拡張機能を使用して参照されているが、コンテナーとして明示的にホストされる必要があるシナリオをサポートするためです。 -
url
: 整形式の URL が必要なサービス間参照の場合。 配置ツールは、マニフェストで定義されているスキーム、プロトコル、トランスポート、およびデプロイされた基になるコンピューティング/ネットワーク トポロジに基づいて、url
を生成します。 -
host
: URL のホスト セグメント。 -
port
: URL のポート セグメント。
リソースの種類
各リソースには、type
フィールドがあります。 配置ツールは、マニフェストを読み取るときに、型を読み取って、マニフェストを正しく処理できるかどうかを確認する必要があります。
.NET
.NET Aspire プレビュー期間中、すべてのリソースの種類には、変更される可能性があることを示す v0
サフィックスがあります。
.NET
.NET Aspire アプローチでは、v1
サフィックスを使用して、そのリソースの種類のマニフェストの構造を安定と見なす必要があることを示します (後続の更新プログラムでは、それに応じてバージョン番号がインクリメントされます)。
共通リソース フィールド
type
フィールドは、すべてのリソースの種類に共通する唯一のフィールドですが、project.v0
、container.v0
、および executable.v0
リソースの種類も、env
フィールドと bindings
フィールドを共有します。
手記
executable.v0
リソースの種類は、配置シナリオでのユーティリティがないため、マニフェストに完全には実装されていません。 実行可能ファイルのコンテナー化の詳細については、Dockerfile リソースの種類を参照してください。
バインドは、bindings
bindings
オブジェクトの下の独自のフィールド内に含まれる各バインドを使用して、JSON フィールドで指定されます。
.NET ノードの .NET Aspirebindings
マニフェストで省略されるフィールドは次のとおりです。
-
scheme
:tcp
、udp
、またはhttp
https
次のいずれかの値です。 -
protocol
: 次のいずれかの値tcp
またはudp
-
transport
:scheme
と同じですが、http
とhttp2
の間であいまいさを解消するために使用されます。 -
containerPort
: 省略すると、既定値はポート 80 になります。
inputs
フィールド
一部のリソースでは、inputs
フィールドが生成されます。 このフィールドは、リソースの入力パラメーターを指定するために使用されます。
inputs
フィールドは、各プロパティがプレースホルダー構造の解決で使用される入力パラメーターである JSON オブジェクトです。 たとえば、connectionString
を持つリソースでは、inputs
フィールドを使用して接続文字列の password
を指定できます。
"connectionString": "Host={<resourceName>.bindings.tcp.host};Port={<resourceName>.bindings.tcp.port};Username=admin;Password={<resourceName>.inputs.password};"
接続文字列プレースホルダーは、password
フィールドから inputs
入力パラメーターを参照します。
"inputs": {
"password": {
"type": "string",
"secret": true,
"default": {
"generate": {
"minLength": 10
}
}
}
}
上記の JSON スニペットは、inputs
フィールドを持つリソースの connectionString
フィールドを示しています。
password
入力パラメーターは文字列型であり、シークレットとしてマークされます。
default
フィールドは、入力パラメーターの既定値を指定するために使用されます。 この場合、既定値は generate
フィールドを使用して生成され、最小長のランダムな文字列が含まれます。
組み込みリソース
次の表は、.NET Aspire チームによって開発された .NET Aspire と拡張機能によって明示的に生成されるリソースの種類の一覧です。
クラウドに依存しないリソースの種類
これらのリソースは、📦Aspireで使用できます。NuGet パッケージ ホストします。
アプリ モデルの使用 | マニフェスト リソースの種類 | 見出しリンク |
---|---|---|
AddContainer | container.v0 |
コンテナー リソースの種類の |
PublishAsDockerFile |
dockerfile.v0 |
リソースの種類 を |
AddDatabase | value.v0 |
リソースの種類 を |
AddMongoDB | container.v0 |
リソースの種類 を |
AddDatabase | value.v0 |
リソースの種類 を |
AddMySql | container.v0 |
リソースの種類 を |
AddDatabase | value.v0 |
リソースの種類 を |
AddPostgres | container.v0 |
リソースの種類 を |
AddProject | project.v0 |
プロジェクト リソースの種類の |
AddRabbitMQ | container.v0 |
リソースの種類 を |
AddRedis | container.v0 |
リソースの種類 を |
AddDatabase | value.v0 |
リソースの種類 を |
AddSqlServer | container.v0 |
リソースの種類 を |
プロジェクト リソースの種類
コード例:
var builder = DistributedApplication.CreateBuilder(args);
var apiservice = builder.AddProject<Projects.AspireApp_ApiService>("apiservice");
マニフェストの例:
"apiservice": {
"type": "project.v0",
"path": "../AspireApp.ApiService/AspireApp.ApiService.csproj",
"env": {
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EXCEPTION_LOG_ATTRIBUTES": "true",
"OTEL_DOTNET_EXPERIMENTAL_OTLP_EMIT_EVENT_LOG_ATTRIBUTES": "true"
},
"bindings": {
"http": {
"scheme": "http",
"protocol": "tcp",
"transport": "http"
},
"https": {
"scheme": "https",
"protocol": "tcp",
"transport": "http"
}
}
}
コンテナー リソースの種類
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddContainer("mycontainer", "myimage")
.WithEnvironment("LOG_LEVEL", "WARN")
.WithHttpEndpoint(3000);
マニフェストの例:
{
"resources": {
"mycontainer": {
"type": "container.v0",
"image": "myimage:latest",
"env": {
"LOG_LEVEL": "WARN"
},
"bindings": {
"http": {
"scheme": "http",
"protocol": "tcp",
"transport": "http",
"containerPort": 3000
}
}
}
}
}
リソースの種類の Dockerfile
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddNodeApp("nodeapp", "../nodeapp/app.js")
.WithHttpEndpoint(hostPort: 5031, env: "PORT")
.PublishAsDockerFile();
先端
マニフェストで PublishAsDockerFile
リソースの種類を生成するには、Dockerfile 呼び出しが必要です。この拡張メソッドは、ExecutableResource 型でのみ使用できます。
マニフェストの例:
{
"resources": {
"nodeapp": {
"type": "dockerfile.v0",
"path": "../nodeapp/Dockerfile",
"context": "../nodeapp",
"env": {
"NODE_ENV": "development",
"PORT": "{nodeapp.bindings.http.port}"
},
"bindings": {
"http": {
"scheme": "http",
"protocol": "tcp",
"transport": "http",
"containerPort": 5031
}
}
}
}
}
リソースの種類の Postgres
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddPostgres("postgres1")
.AddDatabase("shipping");
マニフェストの例:
{
"resources": {
"postgres1": {
"type": "container.v0",
"connectionString": "Host={postgres1.bindings.tcp.host};Port={postgres1.bindings.tcp.port};Username=postgres;Password={postgres1.inputs.password}",
"image": "postgres:16.2",
"env": {
"POSTGRES_HOST_AUTH_METHOD": "scram-sha-256",
"POSTGRES_INITDB_ARGS": "--auth-host=scram-sha-256 --auth-local=scram-sha-256",
"POSTGRES_PASSWORD": "{postgres1.inputs.password}"
},
"bindings": {
"tcp": {
"scheme": "tcp",
"protocol": "tcp",
"transport": "tcp",
"containerPort": 5432
}
},
"inputs": {
"password": {
"type": "string",
"secret": true,
"default": {
"generate": {
"minLength": 10
}
}
}
}
},
"shipping": {
"type": "value.v0",
"connectionString": "{postgres1.connectionString};Database=shipping"
}
}
}
リソースの種類の RabbitMQ
RabbitMQ は、コンテナー リソース container.v0
としてモデル化されています。 次のサンプルは、アプリ モデルに追加される方法を示しています。
var builder = DistributedApplication.CreateBuilder(args);
builder.AddRabbitMQ("rabbitmq1");
前のコードでは、次のマニフェストが生成されます。
{
"resources": {
"rabbitmq1": {
"type": "container.v0",
"connectionString": "amqp://guest:{rabbitmq1.inputs.password}@{rabbitmq1.bindings.tcp.host}:{rabbitmq1.bindings.tcp.port}",
"image": "rabbitmq:3",
"env": {
"RABBITMQ_DEFAULT_USER": "guest",
"RABBITMQ_DEFAULT_PASS": "{rabbitmq1.inputs.password}"
},
"bindings": {
"tcp": {
"scheme": "tcp",
"protocol": "tcp",
"transport": "tcp",
"containerPort": 5672
}
},
"inputs": {
"password": {
"type": "string",
"secret": true,
"default": {
"generate": {
"minLength": 10
}
}
}
}
}
}
}
リソースの種類 Redis
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddRedis("redis1");
マニフェストの例:
{
"resources": {
"redis1": {
"type": "container.v0",
"connectionString": "{redis1.bindings.tcp.host}:{redis1.bindings.tcp.port}",
"image": "redis:7.2.4",
"bindings": {
"tcp": {
"scheme": "tcp",
"protocol": "tcp",
"transport": "tcp",
"containerPort": 6379
}
}
}
}
}
リソースの種類の SQL Server
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddSqlServer("sql1")
.AddDatabase("shipping");
マニフェストの例:
{
"resources": {
"sql1": {
"type": "container.v0",
"connectionString": "Server={sql1.bindings.tcp.host},{sql1.bindings.tcp.port};User ID=sa;Password={sql1.inputs.password};TrustServerCertificate=true",
"image": "mcr.microsoft.com/mssql/server:2022-latest",
"env": {
"ACCEPT_EULA": "Y",
"MSSQL_SA_PASSWORD": "{sql1.inputs.password}"
},
"bindings": {
"tcp": {
"scheme": "tcp",
"protocol": "tcp",
"transport": "tcp",
"containerPort": 1433
}
},
"inputs": {
"password": {
"type": "string",
"secret": true,
"default": {
"generate": {
"minLength": 10
}
}
}
}
},
"shipping": {
"type": "value.v0",
"connectionString": "{sql1.connectionString};Database=shipping"
}
}
}
リソースの種類の MongoDB
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddMongoDB("mongodb1")
.AddDatabase("shipping");
マニフェストの例:
{
"resources": {
"mongodb1": {
"type": "container.v0",
"connectionString": "mongodb://{mongodb1.bindings.tcp.host}:{mongodb1.bindings.tcp.port}",
"image": "mongo:7.0.5",
"bindings": {
"tcp": {
"scheme": "tcp",
"protocol": "tcp",
"transport": "tcp",
"containerPort": 27017
}
}
},
"shipping": {
"type": "value.v0",
"connectionString": "{mongodb1.connectionString}/shipping"
}
}
}
リソースの種類の MySQL
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddMySql("mysql1")
.AddDatabase("shipping");
マニフェストの例:
{
"resources": {
"mysql1": {
"type": "container.v0",
"connectionString": "Server={mysql1.bindings.tcp.host};Port={mysql1.bindings.tcp.port};User ID=root;Password={mysql1.inputs.password}",
"image": "mysql:8.3.0",
"env": {
"MYSQL_ROOT_PASSWORD": "{mysql1.inputs.password}"
},
"bindings": {
"tcp": {
"scheme": "tcp",
"protocol": "tcp",
"transport": "tcp",
"containerPort": 3306
}
},
"inputs": {
"password": {
"type": "string",
"secret": true,
"default": {
"generate": {
"minLength": 10
}
}
}
}
},
"shipping": {
"type": "value.v0",
"connectionString": "{mysql1.connectionString};Database=shipping"
}
}
}
Azure固有のリソースの種類
📦 Aspireでは、次のリソースを使用できます。ホスティング。NuGet パッケージAzure します。
アプリ モデルの使用方法 | マニフェスト リソースの種類 | 見出しリンク |
---|---|---|
AddAzureAppConfiguration | azure.bicep.v0 |
Azure App Configuration リソースの種類 |
AddAzureKeyVault | azure.bicep.v0 |
リソースの種類 を |
AddAzureRedis |
azure.bicep.v0 |
リソースの種類 を |
AddAzureServiceBus | azure.bicep.v0 |
リソースの種類 を |
AddAzureSqlServer(...) |
azure.bicep.v0 |
Azure SQL リソースの種類 |
AddAzureSqlServer(...).AddDatabase(...) |
value.v0 |
Azure SQL リソースの種類 |
AddAzurePostgresFlexibleServer(...) |
azure.bicep.v0 |
リソースの種類 を |
AddAzurePostgresFlexibleServer(...).AddDatabase(...) |
value.v0 |
リソースの種類 を |
AddAzureStorage | azure.storage.v0 |
Azure ストレージ リソースの種類 |
AddBlobs | value.v0 |
Azure ストレージ リソースの種類 |
AddQueues | value.v0 |
Azure ストレージ リソースの種類 |
AddTables | value.v0 |
Azure ストレージ リソースの種類 |
リソースの種類 Azure Key Vault
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureKeyVault("keyvault1");
マニフェストの例:
{
"resources": {
"keyvault1": {
"type": "azure.bicep.v0",
"connectionString": "{keyvault1.outputs.vaultUri}",
"path": "aspire.hosting.azure.bicep.keyvault.bicep",
"params": {
"principalId": "",
"principalType": "",
"vaultName": "keyvault1"
}
}
}
}
リソースの種類 Azure Service Bus
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureServiceBus("sb1")
.AddTopic("topic1", [])
.AddTopic("topic2", [])
.AddQueue("queue1")
.AddQueue("queue2");
マニフェストの例:
{
"resources": {
"sb1": {
"type": "azure.bicep.v0",
"connectionString": "{sb1.outputs.serviceBusEndpoint}",
"path": "aspire.hosting.azure.bicep.servicebus.bicep",
"params": {
"serviceBusNamespaceName": "sb1",
"principalId": "",
"principalType": "",
"queues": [
"queue1",
"queue2"
],
"topics": [
{
"name": "topic1",
"subscriptions": []
},
{
"name": "topic2",
"subscriptions": []
}
]
}
}
}
}
Azure Storage リソースの種類
コード例:
var builder = DistributedApplication.CreateBuilder(args);
var storage = builder.AddAzureStorage("images");
storage.AddBlobs("blobs");
storage.AddQueues("queues");
storage.AddTables("tables");
マニフェストの例:
{
"resources": {
"images": {
"type": "azure.bicep.v0",
"path": "aspire.hosting.azure.bicep.storage.bicep",
"params": {
"principalId": "",
"principalType": "",
"storageName": "images"
}
},
"blobs": {
"type": "value.v0",
"connectionString": "{images.outputs.blobEndpoint}"
},
"queues": {
"type": "value.v0",
"connectionString": "{images.outputs.queueEndpoint}"
},
"tables": {
"type": "value.v0",
"connectionString": "{images.outputs.tableEndpoint}"
}
}
}
Azure Redis リソースの種類
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureRedis("azredis1");
マニフェストの例:
{
"resources": {
"azredis": {
"type": "azure.bicep.v0",
"connectionString": "{azredis.outputs.connectionString}",
"path": "azredis.module.bicep",
"params": {
"principalId": "",
"principalName": ""
}
}
}
}
Azure App Configuration リソースの種類
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureAppConfiguration("appconfig1");
マニフェストの例:
{
"resources": {
"appconfig1": {
"type": "azure.bicep.v0",
"connectionString": "{appconfig1.outputs.appConfigEndpoint}",
"path": "aspire.hosting.azure.bicep.appconfig.bicep",
"params": {
"configName": "appconfig1",
"principalId": "",
"principalType": ""
}
}
}
}
Azure SQL リソースの種類
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzureSqlServer("sql")
.AddDatabase("inventory");
マニフェストの例:
{
"resources": {
"sql": {
"type": "azure.bicep.v0",
"connectionString": "Server=tcp:{sql.outputs.sqlServerFqdn},1433;Encrypt=True;Authentication=\u0022Active Directory Default\u0022",
"path": "sql.module.bicep",
"params": {
"principalId": "",
"principalName": ""
}
},
"inventory": {
"type": "value.v0",
"connectionString": "{sql.connectionString};Database=inventory"
}
}
}
Azure Postgres リソースの種類
コード例:
var builder = DistributedApplication.CreateBuilder(args);
builder.AddAzurePostgresFlexibleServer("postgres")
.AddDatabase("db");
マニフェストの例:
{
"resources": {
"postgres": {
"type": "azure.bicep.v0",
"connectionString": "{postgres.outputs.connectionString}",
"path": "postgres.module.bicep",
"params": {
"principalId": "",
"principalType": "",
"principalName": ""
}
},
"db": {
"type": "value.v0",
"connectionString": "{postgres.connectionString};Database=db"
}
}
}
Azure Developer CLI でサポートされているリソースの種類
Azure Developer CLI (azd) は、.NET Aspire プロジェクトを Azure Container Appsにデプロイするために使用できるツールです。
azure.bicep.v0
リソースの種類では、クラウドに依存しないリソース コンテナーの種類を、Azure固有のリソースにマップできます。 次の表に、Azure Developer CLIでサポートされているリソースの種類を示します。
名前 | クラウドに依存しない API | Azure API |
---|---|---|
Redis | AddRedis | AddAzureRedis |
Postgres | AddPostgres | AddAzurePostgresFlexibleServer |
SQL Server | AddSqlServer | AddAzureSqlServer |
リソースが Azure リソースとして構成されている場合、azure.bicep.v0
リソースの種類がマニフェストに生成されます。 詳細については、「
関連項目
- .NET .NET Aspire の概要
- オーケストレーション .NET.NET Aspire 概要
- .NET .NET Aspire 統合の概要
でのサービス検出の
.NET Aspire