次の方法で共有


Aspire 9.4 の新機能

📢 Aspire 9.4 は、 Aspireの次のマイナー バージョン リリースです。 以下がサポートされています。

  • .NET 8.0 長期サポート (LTS)
  • .NET 9.0 Standard Term Support (STS)
  • .NET 10.0 Preview 6

フィードバックや質問がある場合、または Aspireに貢献したい場合は、 GitHub で共同作業を行うか、新しい Discord に参加して、チームや他のコミュニティ メンバーとチャットしてください。

留意すべき点として、Aspire リリースは .NET リリースとは別に発行されることがあります。 メジャー バージョンの Aspire はメジャー .NET バージョンと一致しますが、マイナー バージョンはより頻繁にリリースされます。 詳細は、.NETおよびAspireバージョンサポートについて参照してください。

⬆️ Aspire 9.4 へのアップグレード

Aspireのマイナー リリース間の移動は簡単です。

  1. AppHost プロジェクト ファイル (つまり MyApp.AppHost.csproj) で、📦Aspire.AppHost.Sdk NuGet パッケージをバージョン 9.4.0に更新します。

    <Sdk Name="Aspire.AppHost.Sdk" Version="9.4.0" />
    

    詳細については、「 Aspire SDK」を参照してください。

  2. Visual Studioの NuGet パッケージ マネージャーまたは VS Code のの C# Dev Kit] コマンドを使用して、NuGet パッケージの更新プログラムを確認します。

  3. 次のAspireコマンド ラインを実行して、最新の.NETに更新します。

    dotnet new install Aspire.ProjectTemplates
    

    dotnet new install コマンドは、既存のAspire テンプレートが既にインストールされている場合、最新バージョンに更新します。

AppHost プロジェクト ファイルに Aspire.AppHost.Sdk 参照がない場合でも、 Aspire 8 を使用している可能性があります。 9 にアップグレードするには、 アップグレード ガイドに従います。

🛠️ Aspire CLI は一般公開されています

Aspire 9.4 のリリースでは、Aspire CLI が一般公開されています。 Aspire CLI を AOT コンパイル 済みバイナリとしてインストールするには、次のヘルパー スクリプトを使用します。

# Bash
curl -sSL https://aspire.dev/install.sh | bash

# PowerShell
iex "& { $(irm https://aspire.dev/install.ps1) }"

これにより、CLI がインストールされ、PATH に配置されます (バイナリは $HOME/.aspire/bin パスに配置されます)。 選択した場合は、次を使用して、非 AOT .NET グローバル ツールとして CLI をインストールすることもできます。

dotnet tool install -g Aspire.Cli

詳細については、「Aspire CLI のインストール」および「アスパイアインストール スクリプト リファレンス」を参照してください

Note

⚠️ Aspire 9.4 CLI は、Aspire 9.3 プロジェクトと互換性がありません。最新の CLI 機能を使用するには、プロジェクトを Aspire 9.4 以降にアップグレードする必要があります。

🎯 CLI コマンド

Aspire CLI には、次のコマンドがあります。

  • aspire new: テンプレートから新しい Aspire プロジェクトを作成します。
  • aspire run: リポジトリ内の任意の場所から既存の apphost を検索して実行します。
  • aspire add: ホスティング統合パッケージを apphost に追加します。
  • aspire config [get|set|delete|list]: Aspire 設定と機能フラグを構成します。
  • aspire publish (プレビュー): apphost に基づいてデプロイ成果物を生成します。

これらのコア コマンドに加えて、 機能フラグの背後には 2 つのベータ コマンドがあります。

  • aspire exec: apphost で定義されている実行可能リソースのコンテキストで任意のコマンドを呼び出します (つまり、環境変数を継承します)。
  • aspire deploy: aspire publish の機能を拡張して、ターゲット環境にアクティブにデプロイします。

aspire exec

新しい exec コマンドを使用すると、 Aspire アプリケーション環境のコンテキスト内でコマンドを実行できます。

# Execute commands, like migrations, with environment variables from your app model
aspire exec --resource my-api -- dotnet ef database update

# Run scripts with access to application context
aspire exec --start-resource my-worker -- npm run build

# The exec command automatically provides environment variables
# from your Aspire application resources to the executed command

主な機能:

  • アプリ モデル リソースからの環境変数の挿入
  • または--resource オプションを使用した--start-resource
  • Aspirified アプリケーションのコンテキストでのコマンドの実行

Important

🧪 機能フラグ: aspire exec コマンドは機能フラグの背後にあり、このリリース では既定で無効になっていますaspire config set features.execCommandEnabled trueで使用するには、明示的に有効にする必要があります。

aspire deploy

aspire deploy コマンドは、新しいDeployingCallbackAnnotationによる拡張可能なデプロイ ワークフローをサポートし、カスタムのデプロイ前/デプロイ後ロジックと、デプロイ操作中の外部システムとのより豊富な統合を可能にします。

主要な機能:

  • カスタム デプロイ フックを使用してDeployingCallbackAnnotationaspire deployコマンド中に実行する
  • ワークフロー アクティビティレポートIPublishingActivityReporter経由で行い、コマンド内の進行状況の通知とプロンプトをサポートします。
  • publish との統合 - aspire deployAspire.Hosting.Publishing.PublishingCallbackAnnotations を実行して、発行手順によって生成された成果物のデプロイをサポートします (該当する場合)

次の例では、 DeployingCallbackAnnotation を使用してカスタムデプロイ動作を登録し、 CLI ベースのプロンプト と進行状況の通知を紹介しています。

#pragma warning disable ASPIREPUBLISHERS001
#pragma warning disable ASPIREINTERACTION001

using Aspire.Hosting.Publishing;
using Microsoft.Extensions.DependencyInjection;

var builder = DistributedApplication.CreateBuilder(args);

// Custom deployment step defined below
builder.AddDataSeedJob("SeedInitialData", seedDataPath: "data/seeds");

builder.Build().Run();

internal class DataSeedJobResource(string name, string seedDataPath)
    : Resource(name)
{
    public string SeedDataPath { get; } = seedDataPath;
}

internal static class DataSeedJobBuilderExtensions
{
    public static IResourceBuilder<DataSeedJobResource> AddDataSeedJob(
        this IDistributedApplicationBuilder builder,
        string name,
        string seedDataPath = "data/seeds")
    {
        var job = new DataSeedJobResource(name, seedDataPath);
        var resourceBuilder = builder.AddResource(job);

        // Attach a DeployingCallbackAnnotation that will be invoked on `aspire deploy`
        job.Annotations.Add(new DeployingCallbackAnnotation(async ctx =>
        {
            CancellationToken ct = ctx.CancellationToken;

            // Prompt the user for a confirmation using the interaction service
            var interactionService = ctx.Services.GetRequiredService<IInteractionService>();

            var envResult = await interactionService.PromptInputAsync(
                "Environment Configuration",
                "Please enter the target environment name:",
                new InteractionInput
                {
                    Label = "Environment Name",
                    InputType = InputType.Text,
                    Required = true,
                    Placeholder = "dev, staging, prod"
                },
                cancellationToken: ct);


            // Use the ActivityReporter to report progress on the seeding process
            var reporter = ctx.ActivityReporter;

            var step = await reporter.CreateStepAsync("Seeding data", ct);
            var task = await step.CreateTaskAsync($"Loading seed data from {seedDataPath}", ct);

            try
            {
                // Do some work here
                await Task.Delay(3000);

                await task.SucceedAsync("Seed data loaded", ct);
                await step.SucceedAsync("Data seeding completed", ct);
            }
            catch (Exception ex)
            {
                await task.FailAsync(ex.Message, ct);
                await step.FailAsync("Data seeding failed", ct);
                throw;
            }
        }));

        return resourceBuilder;
    }
}

このカスタム デプロイ ロジックは、 aspire deploy コマンドから次のように実行されます。

aspire-deploy-whats-new

統合所有者は、高度な aspire deploy ワークフローを作成できるようになりました。 この作業では、高度なデプロイ自動化シナリオの基礎も提供します。

Note

DeployingCallbackAnnotation API は Aspire 9.4 で使用できます。現在、デプロイ コールバックをネイティブにサポートする組み込みリソースはありません。 デプロイ コールバックの組み込みリソースサポートは、次のバージョンの Aspireに追加されます。

Important

🧪 機能フラグ: aspire deploy コマンドは機能フラグの背後にあり、このリリース では既定で無効になっています 。 を使用するには、明示的に有効にする必要があります。 aspire config set features.deployCommandEnabled true

📃 発行とデプロイの出力の強化

Aspire 9.4 は、発行およびデプロイ操作中のフィードバックと進行状況レポートを大幅に改善し、デプロイ プロセス中に何が起こっているかを明確に把握できるようにします。

主な機能強化:

  • 公開中の詳細なステップ バイ ステップ フィードバックによる進行状況レポートの強化
  • デプロイの進行状況に従いやすくする、よりクリーンな出力書式設定
  • デプロイが失敗したときに、よりわかりやすい情報を使用してエラー メッセージを改善する
  • リソースのデプロイ状態を追跡してレポートする発行コンテキストが改善されました
  • コンテナー ビルド ログ では、コンテナー操作中に状態が明確に更新されます

これらの機能強化により、 aspire deploy および aspire publish 操作中に何が起こっているかを理解しやすくなります。これにより、開発者は問題をより効果的にデバッグし、デプロイ プロセスに自信を持つことができるようになります。

拡張出力は、次の場合に特に重要です。

  • トラブルシューティングに明確なログ記録が不可欠な CI/CD パイプライン
  • 複数のリソースと依存関係を持つ複雑なデプロイ
  • ビルド操作とプッシュ操作で明確な状態レポートが必要なコンテナー ベースのデプロイ
  • デプロイ ログをさまざまなチーム メンバーが簡単に解釈する必要があるチーム環境

Aspire アプリ発行と展開の詳細については、「aspire deploy」を参照してください。

🖥️ アプリ モデルの機能強化

🎛️ 対話サービス

Aspire9.4 では、開発者がダッシュボード UX を拡張し、 CLI を使用して発行およびデプロイ時に豊富なエクスペリエンスを実行時に構築できるようにする一般的なサービスであるAspireが導入されています。 これにより、ユーザーからの入力が必要な複雑な対話を構築できます。

Important

🧪 この機能は試験段階であり、今後のリリースで変更される可能性があります。

ダッシュボードでの対話サービスの使用の記録。

対話システムでは、次の機能がサポートされます。

  • 破壊的操作の確認プロンプト
  • 検証を含む入力コレクション
  • 複数ステップのワークフロー
  • 実行モード中のダッシュボード操作
  • デプロイ操作と発行操作中の CLI 操作
// Example usage of IInteractionService APIs
public class DeploymentService
{
    private readonly IInteractionService _interactionService;

    public DeploymentService(IInteractionService interactionService)
    {
        _interactionService = interactionService;
    }

    public async Task DeployAsync()
    {
        // Prompt for confirmation before destructive operations
        var confirmResult = await _interactionService.PromptConfirmationAsync(
            "Confirm Deployment", 
            "This will overwrite the existing deployment. Continue?");

        if (confirmResult.Canceled || !confirmResult.Data)
        {
            return;
        }

        // Collect multiple inputs with validation
        var regionInput = new InteractionInput { Label = "Region", InputType = InputType.Text, Required = true };
        var instanceCountInput = new InteractionInput { Label = "Instance Count", InputType = InputType.Number, Required = true };
        var enableMonitoringInput =  new InteractionInput { Label = "Enable Monitoring", InputType = InputType.Boolean };

        var multiInputResult = await _interactionService.PromptInputsAsync(
            "Advanced Configuration",
            "Configure deployment settings:",
            [regionInput, instanceCountInput, enableMonitoringInput],
            new InputsDialogInteractionOptions
            {
                ValidationCallback = async context =>
                {
                    if (!IsValidRegion(regionInput.Value))
                    {
                        context.AddValidationError(regionInput, "Invalid region specified");
                    }
                }
            });

        if (multiInputResult.Canceled)
        {
            return;
        }

        await RunDeploymentAsync(
            region: regionInput.Value,
            instanceCount: instanceCountInput.Value,
            enableMonitoring: enableMonitoringInput.Value);

        // Show progress notifications
        await _interactionService.PromptNotificationAsync(
            "Deployment Status",
            "Deployment completed successfully!",
            new NotificationInteractionOptions
            {
                Intent = MessageIntent.Success,
                LinkText = "View Dashboard",
                LinkUrl = "https://portal.azure.com"
            });
    }

    private bool IsValidRegion(string? region) 
    {
        // Validation logic here
        return !string.IsNullOrEmpty(region);
    }
}

サポートされている入力の種類:

  • Text - 標準テキスト入力
  • SecretText - パスワード/シークレット入力 (マスク)
  • Choice - ドロップダウンの選択
  • Boolean - チェックボックスの入力
  • Number - 数値入力

高度な機能:

  • 複雑な入力検証用のコールバック
  • リッチ テキストの説明に対する Markdown のサポート
  • カスタム ボタンのテキスト とダイアログ のオプション
  • さまざまなメッセージの種類に対する意図ベースのスタイル設定
  • 通知でリンクのサポート

これらの対話は、 Aspire ダッシュボード を使用してアプリケーションを実行する場合でも、 aspire deploy コマンドと aspire publish コマンドを使用して CLI を使用してデプロイする場合でも、シームレスに機能します。

🔄 実行モード中の対話型パラメータープロンプト

Aspire 9.4 では、対話型のパラメーター プロンプトが導入され、新しい 対話サービスを介してアプリケーションの起動時にダッシュボードで不足しているパラメーター値が自動的に収集されます。

var builder = DistributedApplication.CreateBuilder(args);

// Parameters without default values will trigger prompts
var apiKey = builder.AddParameter("api-key", secret: true);
var dbPassword = builder.AddParameter("db-password", secret: true);

// This also works for values that could be defined in appsettings.json
var environment = builder.AddParameterFromConfiguration("environment", "ENVIRONMENT_VARIABLE");

// Application will prompt for these values if not provided
var database = builder.AddPostgres("postgres", password: dbPassword);
var api = builder.AddProject<Projects.Api>("api")
    .WithEnvironment("API_KEY", apiKey)
    .WithEnvironment("ENVIRONMENT", environment)
    .WithReference(database);

builder.Build().Run();

対話型エクスペリエンス:

  • スタートアップ エラーが発生しないように、不足しているパラメーターを自動的に検出します
  • 対話型フォームと Markdown 対応パラメーターの説明を含むダッシュボード プロンプト
  • 規則の適用に対する検証のサポート (必須、長さ、大文字と小文字など)
  • 機密性の高い入力を入力中に表示せず非表示にするためのマスキング機能
  • ソース管理の外部で永続的なプロジェクトごとの値のストレージをユーザー シークレットに保存する

この機能により、Aspirified アプリケーションを実行する前に appsettings.json ファイルまたは .env ファイル内のすべてのパラメーターを事前に構成する必要がなくなり、完全なスタックを実行するために必要な値を複製、実行、ガイド付けすることができます。

📝 拡張パラメーターの説明とカスタム入力レンダリング

対話型パラメーター プロンプト機能と新しい 対話サービスに基づいて、 Aspire 9.4 では、豊富なパラメーターの説明とカスタム入力レンダリングが導入され、パラメーターの収集時のユーザー ガイダンスと特殊な入力コントロールが向上します。

  • Aspire。Hosting.ParameterResourceBuilderExtensions.WithDescription - パラメーター入力中にユーザーをガイドするための便利な説明を追加する
  • Markdown のサポート - リンク、書式設定、およびリストを使用したリッチ テキストの説明 enableMarkdown: true
  • Aspire。Hosting.ParameterResourceBuilderExtensions.WithCustomInput - 特定のパラメーター型に特化した入力コントロールを作成する
var builder = DistributedApplication.CreateBuilder(args);

// Parameters with descriptions provide better user guidance
var apiKey = builder.AddParameter("api-key", secret: true)
    .WithDescription("API key for external service authentication");

var environment = builder.AddParameter("environment")
    .WithDescription("Target deployment environment (dev, staging, prod)");

// Parameters with rich markdown descriptions
var configValue = builder.AddParameter("config-value")
    .WithDescription("""
        Configuration value with detailed instructions:
        
        - Use **development** for local testing
        - Use **staging** for pre-production validation  
        - Use **production** for live deployments
        
        See [configuration guide](https://docs.company.com/config) for details.
        """, enableMarkdown: true);

// Custom input rendering for specialized scenarios
var workerCount = builder.AddParameter("worker-count")
    .WithDescription("Number of background worker processes")
    .WithCustomInput(p => new InteractionInput
    {
        InputType = InputType.Number,
        Label = "Worker Count",
        Placeholder = "Enter number (1-10)",
        Description = p.Description
    });

var deploymentRegion = builder.AddParameter("region")
    .WithDescription("Azure region for deployment")
    .WithCustomInput(p => new InteractionInput
    {
        InputType = InputType.Choice,
        Label = "Deployment Region",
        Description = p.Description,
        Options = new[]
        {
            KeyValuePair.Create("eastus", "East US"),
            KeyValuePair.Create("westus", "West US"),
            KeyValuePair.Create("northeurope", "North Europe"),
            KeyValuePair.Create("southeastasia", "Southeast Asia")
        }
    });

var api = builder.AddProject<Projects.Api>("api")
    .WithEnvironment("API_KEY", apiKey)
    .WithEnvironment("ENVIRONMENT", environment)
    .WithEnvironment("CONFIG_VALUE", configValue)
    .WithEnvironment("WORKER_COUNT", workerCount)
    .WithEnvironment("REGION", deploymentRegion);

builder.Build().Run();

サポートされている入力の種類を含む詳細については、以下の 「Interaction Service」セクション または完全な 対話サービスのドキュメントを参照してください。

🌐 外部サービス モデリング

最新のアプリケーションは、多くの場合、外部 API、サードパーティのサービス、または Aspireによって管理されていない既存のインフラストラクチャと統合する必要があります。 Aspire 9.4 では、アプリケーション グラフのリソースとして 外部サービスをモデル化するための ファースト クラスのサポートが導入されています。

var builder = DistributedApplication.CreateBuilder(args);

// Reference an external service by URL
var externalApi = builder.AddExternalService("external-api", "https://api.company.com");

// Or use a parameter for dynamic configuration
var apiUrl = builder.AddParameter("api-url");
var externalDb = builder.AddExternalService("external-db", apiUrl)
    .WithHttpHealthCheck("/health");

var myService = builder.AddProject<Projects.MyService>("my-service")
    .WithReference(externalApi)
    .WithReference(externalDb);

builder.Build().Run();

外部サービスは、正常性状態を持つ Aspire ダッシュボードに表示され、他のリソースと同様に参照でき、内部リソースと同じ構成パターンをサポートします。

🔗 エンドポイント URL のサポートの強化

Aspire9.4 では、localhost以外の URL のサポートが導入されているため、カスタム ドメインとネットワーク構成を簡単に操作できます。 これには、 *.localhost サブドメインのサポートと、複数のアドレスでリッスンするエンドポイントの複数の URL バリアントの自動生成が含まれます。

var builder = DistributedApplication.CreateBuilder(args);

// Endpoints targeting all addresses automatically get multiple URL variants
var api = builder.AddProject<Projects.Api>("api")
    .WithEndpoint("https", e => e.TargetHost = "0.0.0.0");

// Machine name URLs for external access  
var publicService = builder.AddProject<Projects.PublicService>("public")
    .WithEndpoint("https", e => e.TargetHost = "0.0.0.0");

builder.Build().Run();

主要な機能:

  • *.localhost動作を維持する
  • 自動エンドポイント URL 生成は、複数のアドレスでリッスンするエンドポイントに対して、localhostおよびマシン名 URL (Codespaces など) を使用して行います。
  • 簡単にアクセスできるように、すべての URL バリアント が Aspire ダッシュボードに表示されます
  • 特定のネットワーク構成を必要とする開発シナリオのネットワークの柔軟性
  • 起動プロファイル構成のサポート により、 launchSettings.jsonの起動プロファイルを使用してカスタム URL を構成することもできます。
{
  "profiles": {
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://*:7001;http://*:5001",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

これにより、使い慣れた localhost 開発エクスペリエンスを維持しながら、カスタム ドメインまたは外部ネットワーク アクセスが必要な開発ワークフローが簡略化されます。 一般的な例には、テナントごとのカスタム ドメインを使用する SaaS ソリューションが含まれます。

🐳 永続的なコンテナーのサポートの強化

Aspire 9.4 は、ライフサイクル管理とネットワーク機能が向上した 永続的なコンテナー のサポートを向上させ、適切な接続を維持しながら、アプリケーションの再起動間でコンテナーを保持できるようにします。

var builder = DistributedApplication.CreateBuilder(args);

// Persistent containers with improved lifecycle support
var database = builder.AddPostgres("postgres")
    .WithLifetime(ContainerLifetime.Persistent)
    .WithExplicitStart(); // Better support for explicit start with persistent containers

// Persistent containers automatically also get persistent networking
var redis = builder.AddRedis("redis")
    .WithLifetime(ContainerLifetime.Persistent);

var api = builder.AddProject<Projects.Api>("api")
    .WithReference(database)
    .WithReference(redis);

builder.Build().Run();

強化された機能:

  • ライフサイクル調整の改善WithExplicitStart
  • 永続コンテナーが検出された際に自動的に起動される永続ネットワーク
  • より信頼性の高いスタートアップ シーケンス処理のためのコンテナー遅延開始
  • 永続的コンテナーとセッション スコープ コンテナー間のネットワーク分離。リソース管理を強化するために個別のネットワークを使用するようになりました

これにより、個々のアプリケーションの実行を超えて永続化されるステートフル サービスを構築しながら、エクスペリエンスが大幅に向上します。

🎛️ リソース コマンド サービス

Aspire 9.4 には、リソースに対してコマンドを実行するための API ResourceCommandServiceが導入されています。 ダッシュボードに表示されるコマンドをプログラムで簡単に実行できるようになりました。 たとえば、コマンドの単体テストを記述する場合や、Aspire において他の統合がコマンドを実行する場合などです。

次の例では、コマンドが他のコマンドを実行するのに ResourceCommandService を使用します。

var builder = DistributedApplication.CreateBuilder(args);

var database = builder.AddPostgres("postgres")
    .WithHttpCommand("admin-restart", "Restart Database", 
        commandName: "db-restart",
        commandOptions: new HttpCommandOptions
        {
            Method = HttpMethod.Post,
            Description = "Restart the PostgreSQL database"
        });

var cache = builder.AddRedis("cache")
    .WithHttpCommand("admin-flush", "Flush Cache",
        commandName: "cache-flush",
        commandOptions: new HttpCommandOptions
        {
            Method = HttpMethod.Delete,
            Description = "Clear all cached data"
        });

// Add a composite command that coordinates multiple operations
var api = builder.AddProject<Projects.Api>("api")
    .WithReference(database)
    .WithReference(cache)
    .WithCommand("reset-all", "Reset Everything", async (context, ct) =>
    {
        var logger = context.ServiceProvider.GetRequiredService<ILogger<Program>>();
        var commandService = context.ServiceProvider.GetRequiredService<ResourceCommandService>();
        
        logger.LogInformation("Starting full system reset...");
        
        try
        {
            var flushResult = await commandService.ExecuteCommandAsync(cache.Resource, "cache-flush", ct);
            var restartResult = await commandService.ExecuteCommandAsync(database.Resource, "db-restart", ct);
            if (!restartResult.Success || !flushResult.Success)
            {
                return CommandResults.Failure($"System reset failed");
            }
            
            logger.LogInformation("System reset completed successfully");
            return CommandResults.Success();
        }
        catch (Exception ex)
        {
            logger.LogError(ex, "System reset failed");
            return CommandResults.Failure(ex);
        }
    },
    displayDescription: "Reset cache and restart database in coordinated sequence",
    iconName: "ArrowClockwise");

builder.Build().Run();

ResourceCommandService は単体テストでも使用できます。

[Fact]
public async Task Should_ResetCache_WhenTestStarts()
{
    var builder = DistributedApplication.CreateBuilder();
    
    // Add cache with reset command for testing
    var cache = builder.AddRedis("test-cache")
        .WithHttpCommand("reset", "Reset Cache",
            commandName: "reset-cache",
            commandOptions: new HttpCommandOptions
            {
                Method = HttpMethod.Delete,
                Description = "Clear all cached test data"
            });

    var api = builder.AddProject<Projects.TestApi>("test-api")
        .WithReference(cache);

    await using var app = builder.Build();
    await app.StartAsync();
    
    // Reset cache before running test
    var result = await app.ResourceCommands.ExecuteCommandAsync(
        cache.Resource, 
        "reset-cache", 
        CancellationToken.None);
        
    Assert.True(result.Success, $"Failed to reset cache: {result.ErrorMessage}");
}

🔄 リソース ライフサイクル イベント

Aspire 9.4 では、 IResourceBuilder<T> に便利な拡張メソッドが導入されており、リソースで 直接ライフサイクル イベント をサブスクライブしやすくなり、よりクリーンで直感的な API が提供されます。

var builder = DistributedApplication.CreateBuilder(args);

var database = builder.AddPostgres("postgres")
                .AddDatabase("mydb")
                .OnConnectionStringAvailable(async (resource, evt, cancellationToken) =>
                {
                    // Log when connection strings are resolved
                    var logger = evt.Services.GetRequiredService<ILogger<Program>>();
                    logger.LogInformation("Connection string available for {Name}", resource.Name);
                });

var api = builder.AddProject<Projects.Api>("api")
                .WithReference(database)
                .OnInitializeResource(async (resource, evt, cancellationToken) =>
                {
                    // Early resource initialization
                    var logger = evt.Services.GetRequiredService<ILogger<Program>>();
                    logger.LogInformation("Initializing resource {Name}", resource.Name);
                })
                .OnBeforeResourceStarted(async (resource, evt, cancellationToken) =>
                {
                    // Pre-startup validation or configuration
                    var serviceProvider = evt.Services;
                    // Additional validation logic here
                })
                .OnResourceEndpointsAllocated(async (resource, evt, cancellationToken) =>
                {
                    // React to endpoint allocation
                    var logger = evt.Services.GetRequiredService<ILogger<Program>>();
                    logger.LogInformation("Endpoints allocated for {Name}", resource.Name);
                })
                .OnResourceReady(async (resource, evt, cancellationToken) =>
                {
                    // Resource is fully ready
                    var logger = evt.Services.GetRequiredService<ILogger<Program>>();
                    logger.LogInformation("Resource {Name} is ready", resource.Name);
                });

// Example: Database seeding using OnResourceReady
var db = builder.AddMongoDB("mongo")
    .WithMongoExpress()
    .AddDatabase("db")
    .OnResourceReady(async (db, evt, ct) =>
    {
        // Seed the database with initial data
        var connectionString = await db.ConnectionStringExpression.GetValueAsync(ct);
        using var client = new MongoClient(connectionString);
        
        var myDb = client.GetDatabase("db");
        await myDb.CreateCollectionAsync("entries", cancellationToken: ct);
        
        // Insert sample data
        for (int i = 0; i < 10; i++)
        {
            await myDb.GetCollection<Entry>("entries").InsertOneAsync(new Entry(), cancellationToken: ct);
        }
    });

builder.Build().Run();

使用可能なライフサイクル イベント:

新しいチェーン可能な fluent API、厳密に型指定されたコールバック、および簡略化された構文により、操作、コマンド、カスタム スクリプトなどのリソース ライフサイクルに直感的にフックできます。

手動イベントからの移行:

// ❌ Before (manual eventing subscription):
builder.Eventing.Subscribe<ResourceReadyEvent>(db.Resource, async (evt, ct) =>
{
    // Manual event handling with no type safety
    var cs = await db.Resource.ConnectionStringExpression.GetValueAsync(ct);
    // Process event...
});

// ✅ After (fluent extension methods):
var db = builder.AddMongoDB("mongo")
    .AddDatabase("db")
    .OnResourceReady(async (db, evt, ct) =>
    {
        // Direct access to strongly-typed resource
        var cs = await db.ConnectionStringExpression.GetValueAsync(ct);
        // Process event...
    });

新しい拡張メソッドを使用すると、データベースのシード処理、構成検証、リソース正常性チェックなどの一般的なパターンを簡単に実装できます。 古いメカニズムは非推奨とされていないことに注意してください。新しいメソッドは、ビルダー パターンを使用するときに、より自然なプログラミング モデルを提供するだけです。

📁 拡張コンテナー ファイルのマウント

コンテナー ファイル システムを構成するには、多くの場合、複雑な Docker ボリューム構文を理解し、ファイルのアクセス許可を手動で管理する必要があります。 Aspire 9.4 では、適切な既定値を使用して一般的なシナリオを処理する拡張ファイル マウント API が導入されています。

var builder = DistributedApplication.CreateBuilder(args);

// Simple file copying from local source to container
var myContainer = builder.AddContainer("myapp", "myapp:latest")
    .WithContainerFiles("/app/config", "./config-files")
    .WithContainerFiles("/app/data", "./data", defaultOwner: 1000, defaultGroup: 1000)
    .WithContainerFiles("/app/scripts", "./scripts", umask: UnixFileMode.UserRead | UnixFileMode.UserWrite);

// You can also use the callback approach for dynamic file generation
var dynamicContainer = builder.AddContainer("worker", "worker:latest")
    .WithContainerFiles("/app/runtime-config", async (context, ct) =>
    {
        // Generate configuration files dynamically
        var configFile = new ContainerFileSystemItem
        {
            Name = "app.json",
            Contents = JsonSerializer.SerializeToUtf8Bytes(new { Environment = "Production" })
        };
        
        return new[] { configFile };
    });

builder.Build().Run();

拡張 API は、ファイルのアクセス許可、所有権を処理し、必要に応じてカスタマイズする柔軟性を維持しながら、静的および動的なファイルマウント機能の両方を提供します。

✨ 変換 API を使用した高度な YARP ルーティング (プレビュー)

Note

YARP 統合は現在プレビュー段階であり、API は将来のリリースで変更される可能性があります。

高度なリバース プロキシ構成の構築には、従来、YARP の変換システムと手動の JSON 構成に関する深い知識が必要とされています。 Aspire 9.4 には、厳密に型指定された C# コードを介して高度なルーティング変換にアクセスできるようにする、包括的な Fluent API のセットが導入されています。

9.4 での破壊的変更:WithConfigFile() メソッドは削除され、コード ベースの構成モデルに置き換えられました。 この新しいアプローチは、厳密に型指定された構成方法が適切な環境変数に直接変換されるため、デプロイ シナリオとシームレスに連携します。

アプリ モデルから直接、要求/応答変換、ヘッダー操作、パスの書き換え、クエリ文字列の処理をプログラムで構成できるようになりました。複雑な構成ファイルを使用する必要はありません。

例 1: パス プレフィックスを削除した単純なパスベースのルーティング

var builder = DistributedApplication.CreateBuilder(args);

var apiV1 = builder.AddProject<Projects.ApiV1>("api-v1");
var apiV2 = builder.AddProject<Projects.ApiV2>("api-v2");

var yarp = builder.AddYarp("gateway")
    .WithConfiguration(yarpBuilder =>
    {
        // Route /v1/* requests to api-v1, removing the /v1 prefix
        yarpBuilder.AddRoute("/v1/{**catch-all}", apiV1)
            .WithTransformPathRemovePrefix("/v1");

        // Route /v2/* requests to api-v2, removing the /v2 prefix  
        yarpBuilder.AddRoute("/v2/{**catch-all}", apiV2)
            .WithTransformPathRemovePrefix("/v2");
    });

builder.Build().Run();

例 2: ホストベースのルーティング

var builder = DistributedApplication.CreateBuilder(args);

var adminApi = builder.AddProject<Projects.AdminApi>("admin-api");
var publicApi = builder.AddProject<Projects.PublicApi>("public-api");

var yarp = builder.AddYarp("gateway")
    .WithConfiguration(yarpBuilder =>
    {
        // Route admin.example.com to admin API
        yarpBuilder.AddRoute(adminApi)
            .WithMatchHosts("admin.example.com");

        // Route api.example.com to public API  
        yarpBuilder.AddRoute(publicApi)
            .WithMatchHosts("api.example.com");

        // Default route for any other host
        yarpBuilder.AddRoute("/{**catch-all}", publicApi);
    });

builder.Build().Run();

例 3: 包括的な変換による高度なルーティング

var builder = DistributedApplication.CreateBuilder(args);

var backendApi = builder.AddProject<Projects.BackendApi>("backend-api");
var identityService = builder.AddProject<Projects.Identity>("identity-service");

var yarp = builder.AddYarp("gateway")
    .WithConfiguration(yarpBuilder =>
    {
        // Configure sophisticated routing with transforms
        yarpBuilder.AddRoute("/api/v1/{**catch-all}", backendApi)
            .WithTransformPathPrefix("/v2")  // Rewrite /api/v1/* to /v2/*
            .WithTransformRequestHeader("X-API-Version", "2.0")
            .WithTransformForwarded(useHost: true, useProto: true)
            .WithTransformResponseHeader("X-Powered-By", "Aspire Gateway");

        // Advanced header and query manipulation
        yarpBuilder.AddRoute("/auth/{**catch-all}", identityService)
            .WithTransformClientCertHeader("X-Client-Cert")
            .WithTransformQueryValue("client_id", "aspire-app")
            .WithTransformRequestHeadersAllowed("Authorization", "Content-Type")
            .WithTransformUseOriginalHostHeader(false);
    });

builder.Build().Run();

YARP 9.3 から 9.4 への移行

WithConfigFile() 9.3 でAspireを使用していた場合は、上記の新しいコードベースの構成モデルに移行する必要があります。 厳密に型指定された API は、IntelliSense のサポートを強化し、デプロイ シナリオとシームレスに連携します。

Note

デプロイ時にファイル ベースの構成のためのより汎用的なソリューションに取り組んでいます。 ファイル ベースの構成のサポートは、将来のバージョンの Aspireで返されます。

これにより、複雑な YARP 構成ファイルを必要とせずに、Fluent API を介して YARP の強力な変換パイプラインに完全にアクセスできます。

🔒 Docker Compose の展開セキュリティの強化

Aspire 9.4 はスマート ポート マッピングを使用して Dockerを強化します。外部エンドポイントのみがホストに公開され、内部サービスはDockerの内部ネットワークを利用します。

var builder = DistributedApplication.CreateBuilder(args);

var compose = builder.AddDockerComposeEnvironment("production");

// Add a service with both internal and external endpoints
var webService = builder.AddContainer("webservice", "nginx")
    .WithEndpoint(scheme: "http", port: 8080, name: "internal")       // Internal endpoint
    .WithEndpoint(scheme: "http", port: 8081, name: "api", isExternal: true); // External endpoint

builder.Build().Run();

生成された Docker Compose 出力:

services:
  webservice:
    image: "nginx:latest"
    ports:
      - "8081:8001"    # Only external endpoints get port mappings (host:container)
    expose:
      - "8000"         # Internal endpoints use expose (container port only)
    networks:
      - "aspire"

現在、 isExternal: true エンドポイントのみがホストに公開され、内部エンドポイントはコンテナー間通信に Dockerの expose を使用します。

🎨 ダッシュボードの機能強化

Tip

9.4ダッシュボードの多くの変更を紹介するために、James Newton-King は日々1つの新しいダッシュボード機能を投稿し、自身のAspireでのリリースに向けて継続しています。

🔔 自動アップグレード チェック通知

Aspire 9.4 には、新しいバージョンを自動的にチェックし、更新プログラムが利用可能になったときに開発者に通知する更新通知システムが含まれており、最新の機能強化とセキュリティ更新プログラムを常に最新の状態に保ちます。

新しいバージョンが検出されると、 Aspire ダッシュボードにわかりやすい通知が表示されます。

更新通知を示すダッシュボードのスクリーンショット。

Aspire では、新しいバージョンが使用可能な場合にのみ通知が表示され、アプリケーションの起動やパフォーマンスに影響を与えずにバックグラウンドでチェックが行われます。 ASPIRE_VERSION_CHECK_DISABLED環境変数をtrueに設定することで、アップグレード チェック システムを無効にすることができます。 詳細については、バージョン更新通知Aspire参照してください。

📋 ダッシュボードに表示されるパラメーターと接続文字列

Aspire 9.4 では、パラメーターと接続文字列が Aspire ダッシュボードに表示され、開発中のアプリケーションの構成と接続状態をより詳細に把握できます。

接続文字列:

  • リソースの詳細パネルに表示されます IResourceWithConnectionString を実装するリソースに
  • 値は 機密 としてマークされ、ダッシュボードで表示を切り替えることができます
  • データベース、メッセージ ブローカー、カスタム リソースなど、すべてのリソースの種類をサポートします

接続文字列を示すダッシュボードのスクリーンショット。

外部パラメーターは非表示ではなくなりました。 パラメーターの状態と値がダッシュボードに表示されます。

パラメーターを示すダッシュボードのスクリーンショット。

詳細については、 外部パラメーターを参照してください。

🔗 未計装リソースに対するダッシュボード・ピアの可視化の強化

Aspire 9.4 では、テレメトリでインストルメント化されていないリソース間の接続を観察できます。

たとえば、次のスクリーンショットは、GitHubのモデル リソースに解決するAspire モデルの呼び出しを示しています。

GitHubで定義されているAspire モデル リソースにリンクされているスパンのスクリーンショット。

OpenTelemetry スパンは、パラメーター、接続文字列、GitHub モデル、および外部サービスによって定義されたピアに解決できるようになりました。

  • 接続文字列の解析 では、 SQL Server、 PostgreSQL、 MySQL、 MongoDB、 Redis、およびその他の多くの接続文字列形式がサポートされます
  • URL または接続文字列を使用してパラメーターを視覚化し、サービスに接続する方法
  • 適切な状態管理を使用したGitHubホスト型 AI モデルのGitHub
  • あなたのサービスと外部依存関係 の間の外部サービスのマッピング

📋 コンソールログのテキスト折り返し制御

Aspire 9.4 では、テキストの折り返し動作を制御するための新しいトグル オプションがダッシュボード コンソールログに導入され、ログ行の表示期間をより適切に制御できます。

コンソール ログ ページで行の折り返し切り替えを記録。

一部の Aspire ユーザーは、大きなコンソールログの表示に問題があり、これはこの GitHub の問題で追跡されています: コンソールログが表示されない、加えてブラウザウィンドウのサイズが表示されるログに影響を与える #7969。 ログに問題がある場合は、ラッピングを無効にして、ユーザー エクスペリエンスが向上するかどうかを試してみてください。 この問題に関するフィードバックは非常に役立ちます。

👁️ ダッシュボードで非表示のリソースを表示/非表示にする

Aspire 9.4 では、ダッシュボードで非表示のリソースを表示または非表示にする機能が導入されており、通常は非表示になっているアプリケーションのインフラストラクチャ コンポーネントと内部リソースを完全に可視化できます。

非表示のリソース UI を表示/非表示にするダッシュボード リソース ページ。

Aspire アプリに非表示のリソースがない場合、UI の表示/非表示は無効になります。

🏗️ プロキシされたエンドポイントを使用した強化されたダッシュボード インフラストラクチャ

Aspire 9.4 では、ダッシュボード システムにインフラストラクチャの大幅な改善が導入され、プロキシ処理されたエンドポイントが実装され、ダッシュボードの起動の信頼性が向上し、ポートの再利用の問題が回避されます。 このアーキテクチャの強化により、アプリケーションの起動とシャットダウンのシナリオ中のダッシュボード接続に関する問題が解決されます。 ダッシュボードが再接続しようとしている UI も、より信頼性が高く、新しいまとまりのある外観とアニメーションで更新されています。

🐳 Docker 統合された Aspire ダッシュボードを使用して作成する

多くの場合、 Docker Compose 環境で可観測性を管理するには、個別の監視ツールを実行するか、開発中に Aspire 提供される豊富な分析情報を失う必要があります。 Aspire9.4 では、Aspire Compose 環境用のネイティブ Docker ダッシュボード統合が導入されています。

var builder = DistributedApplication.CreateBuilder(args);

var compose = builder.AddDockerComposeEnvironment("production")
                    .WithDashboard(dashboard => dashboard.WithHostPort(8080)); // Configure dashboard with specific port

// Add services that will automatically report to the dashboard
builder.AddProject<Projects.Frontend>("frontend");
builder.AddProject<Projects.Api>("api");

builder.Build().Run();

🔗 更新された統合

🐙 GitHub モデルの統合

Aspire9.4 では、GitHub モデルのサポートが導入され、GitHubのプラットフォームでホストされている AI モデルとの簡単な統合が可能になります。 これにより、 GitHubのモデル ホスティング サービスを使用して、アプリケーションに AI 機能を簡単に組み込むことができます。

var builder = DistributedApplication.CreateBuilder(args);

// Add GitHub Model - API key parameter is automatically created
var model = builder.AddGitHubModel("chat-model", "gpt-4o-mini");

// You can also specify an API key explicitly if needed
var apiKey = builder.AddParameter("github-api-key", secret: true);
var explicitModel = builder.AddGitHubModel("explicit-chat", "gpt-4o-mini")
    .WithApiKey(apiKey);

// Use the model in your services
var chatService = builder.AddProject<Projects.ChatService>("chat")
    .WithReference(model);

builder.Build().Run();

GitHub モデルの統合では、次の機能が提供されます。

  • のホスト型 AI モデルとのGitHub
  • パターンを使用した API キー パラメーターの自動作成{name}-gh-apikey
  • カスタム シナリオでを使用するWithApiKey()
  • 明示的な API キーが指定されていない場合の GITHUB_TOKEN フォールバック
  • モデルの可用性に関する組み込みの正常性チェック

🤖 Azure AI Foundry 統合

Aspire 9.4 では、包括的な Azure AI Foundry サポートが導入され、エンタープライズ AI 機能が分散アプリケーションに直接導入されます。 この統合により、 Azure AI プラットフォームを介した AI モデルとデプロイの操作が簡素化され、 Azureホスト型デプロイと Foundry Local でのローカル開発の両方がサポートされます。

ホスティング構成

var builder = DistributedApplication.CreateBuilder(args);

// Add Azure AI Foundry project
var foundry = builder.AddAzureAIFoundry("foundry");

// Add specific model deployments
var chat = foundry.AddDeployment("chat", "qwen2.5-0.5b", "1", "Microsoft");
var embedding = foundry.AddDeployment("embedding", "text-embedding-ada-002", "2", "OpenAI");

// Connect your services to AI capabilities
var webService = builder.AddProject<Projects.WebService>("webservice")
    .WithReference(chat)
    .WaitFor(chat);

builder.Build().Run();
Azure AI Foundry ローカル サポート

Azure AI Foundry Local は、ハードウェア上でモデルをローカルで実行するデバイス上の AI 推論ソリューションであり、 Azure サブスクリプションを必要とせずにパフォーマンス、プライバシー、コストの利点を提供します。 データのプライバシー、オフライン操作、コスト削減、または待機時間の短い応答を必要とするシナリオに最適です。

var builder = DistributedApplication.CreateBuilder(args);

// For local development, run with Foundry Local
var localFoundry = builder.AddAzureAIFoundry("foundry")
    .RunAsFoundryLocal()
    .AddDeployment("chat", "phi-3.5-mini", "1", "Microsoft");

var webService = builder.AddProject<Projects.WebService>("webservice")
    .WithReference(localFoundry)
    .WaitFor(localFoundry);

builder.Build().Run();

Client 統合

AppHost で Azure AI Foundry リソースを構成したら、AzureAI 推論 SDK または互換性のあるモデル用の OpenAI SDK を使用してサービスで使用します。

Azure AI 推論 SDK の使用:

// In Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.AddAzureChatCompletionsClient("chat")
       .AddChatClient();

var app = builder.Build();

// Minimal API endpoint for chat completion
app.MapPost("/generate", async (IChatClient chatClient, ChatRequest request) =>
{
    var messages = new List<ChatMessage>
    {
        new(ChatRole.System, "You are a helpful assistant."),
        new(ChatRole.User, request.Prompt)
    };

    var response = await chatClient.GetResponseAsync(messages);
    return Results.Ok(new { Response = response.Text });
});

app.Run();

public record ChatRequest(string Prompt);

OpenAI SDK の使用 (互換性のあるモデルの場合):

// In Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.AddOpenAIClient("chat")
       .AddChatClient();

// Usage is identical to the Azure AI Inference SDK example above

Azure AI Foundry と Foundry Local の主な違い:

  • Azure AI Foundry - クラウドでホストされるモデルは、エンタープライズ レベルのスケーリングを備え、すべての AI モデルのデプロイをサポートします
  • Foundry Local - ローカル ハードウェア用に最適化された異なるモデル選択を使用したオンデバイス推論。 Azure サブスクリプションは必要ありません

RunAsFoundryLocal()メソッドを使用すると、Azure AI Foundry Local を使用したローカル開発シナリオが可能になり、開発中にクラウド リソースを必要とせずに AI 機能をテストできます。 これにより、統合された Foundry Local ランタイムを介したモデルの自動ダウンロード、読み込み、および管理がサポートされます。

🗄️ データベース ホスティングの機能強化

いくつかのデータベース統合が、 改善された初期化パターンで更新されました。

var builder = DistributedApplication.CreateBuilder(args);

// MongoDB - new WithInitFiles method (replaces WithInitBindMount)
var mongo = builder.AddMongoDB("mongo")
    .WithInitFiles("./mongo-init");  // Initialize with scripts

// MySQL - improved initialization with better file handling
var mysql = builder.AddMySql("mysql", password: builder.AddParameter("mysql-password"))
    .WithInitFiles("./mysql-init");  // Initialize with SQL scripts

// Oracle - enhanced setup capabilities with consistent API
var oracle = builder.AddOracle("oracle")
    .WithInitFiles("./oracle-init");  // Initialize with Oracle scripts

builder.Build().Run();

すべてのデータベース プロバイダーで WithInitFiles() メソッドがサポートされるようになりました。これにより、より複雑な WithInitBindMount() メソッドが置き換わり、エラー処理が向上します。

☁️ Azure のお楽しみ

🏷️ 一貫性のあるリソース名の公開

Aspire9.4 では、Azure プロパティを通じて、すべてのNameOutputReference リソースの実際の名前が一貫して公開されるようになりました。 これにより、アプリケーションはデプロイ時に生成される実際の Azure リソース名にアクセスできます。これは、直接 Azure リソース調整を必要とするシナリオに不可欠です。 これは、リソースを実際の名前で参照する外部自動化スクリプトや監視およびアラート システムにとって特に重要です。

🗄️ Azure Cosmos DB

階層パーティション キー

Aspire9.4 では、AzureでのAzure Cosmos DB (サブパーティション分割) のサポートが導入され、データ分散とクエリのパフォーマンスを向上させるために複数レベルのパーティション分割が可能になります。

var builder = DistributedApplication.CreateBuilder(args);

var cosmos = builder.AddAzureCosmosDB("cosmos");
var database = cosmos.AddCosmosDatabase("ecommerce");

// Traditional single partition key
var ordersContainer = database.AddContainer("orders", "/customerId");

// New hierarchical partition keys (up to 3 levels)
var productsContainer = database.AddContainer("products", 
    ["/category", "/subcategory", "/brand"]);

// Multi-tenant scenario
var eventsContainer = database.AddContainer("events",
    ["/tenantId", "/userId", "/sessionId"]);

builder.Build().Run();

主な利点:

  • 複数レベルの分散を使用して、論理パーティションあたり 20 GB を超えてスケーリングする
  • 関連するパーティションへの効率的なルーティングによるクエリ パフォーマンスの向上
  • 多次元データセットのデータ分散の向上
  • 論理パーティション プレフィックスあたり最大 10,000 + RU/秒のスケーラビリティが強化されました

設計パターンとベスト プラクティスに関する詳細なガイダンスについては、 AzureAzure Cosmos DB 階層パーティション キーのドキュメントを参照してください

サーバーレスのサポート

Azure Azure Cosmos DB アカウントが既定でサーバーレス モードに設定され、使用量ベースの課金によるコストの最適化が行われます。

// Default behavior: Creates serverless account (new in 9.4)
var cosmos = builder.AddAzureCosmosDB("cosmos");

// Explicitly enable provisioned throughput mode
var provisionedCosmos = builder.AddAzureCosmosDB("cosmos")
    .WithDefaultAzureSku(); // Uses provisioned throughput instead of serverless

サーバーレスの利点:

  • 従量課金 制 - 消費された要求ユニットとストレージに対してのみ課金されます
  • 最小コストなし - 断続的または予測不可能なワークロードに最適
  • 自動スケーリング - 容量計画は必要ありません
  • 開発環境/テスト環境に最適

次の場合にサーバーレスを使用します。 変動するワークロード、開発/テスト、トラフィックの平均対ピーク率が低いアプリケーション。
プロビジョニングされたスループットを次の目的で使用します。 予測可能なパフォーマンスの保証を必要とする継続的なトラフィック。

比較と制限の詳細については、サーバーレスドキュメントAzureAzure Cosmos DB参照してください

🆔 一貫性のあるユーザー割り当てマネージド ID のサポート

Aspire 9.4 では、 Azure ユーザー割り当てマネージド ID の包括的なサポートが導入され、 Azure インフラストラクチャ全体でセキュリティが強化され、一貫性のある ID 管理が提供されます。

var builder = DistributedApplication.CreateBuilder(args);

// Create a user-assigned managed identity
var appIdentity = builder.AddAzureUserAssignedIdentity("app-identity");

// Create the container app environment
var containerEnv = builder.AddAzureContainerAppEnvironment("container-env");

// Apply the identity to compute resources
var functionApp = builder.AddAzureFunctionsProject<Projects.Functions>("functions")
    .WithAzureUserAssignedIdentity(appIdentity);

// The identity can be shared across multiple resources
var webApp = builder.AddProject<Projects.WebApp>("webapp")
    .WithAzureUserAssignedIdentity(appIdentity);

// Use the same identity for accessing Azure services
var keyVault = builder.AddAzureKeyVault("secrets");
var storage = builder.AddAzureStorage("storage");

// Services using the shared identity can access resources securely
var processor = builder.AddProject<Projects.DataProcessor>("processor")
    .WithAzureUserAssignedIdentity(appIdentity)
    .WithReference(keyVault)
    .WithReference(storage);

builder.Build().Run();

このアプローチでは、次の機能が提供されます。

  • 柔軟な ID 制御 - 特定の ID 構成が必要な場合に Aspireのセキュリティで保護された既定値をオーバーライドする
  • すべてのコンピューティング リソースで一貫した ID 管理

🔐 マネージド ID を適用するためにローカル認証を無効にしました

Aspire9.4 では、Azure Web PubSub リソースのローカル認証が自動的に無効になり、既定でマネージド ID 認証が適用されます。

var builder = DistributedApplication.CreateBuilder(args);

// Azure EventHubs with automatic local auth disabled
var eventHubs = builder.AddAzureEventHubs("eventhubs");
var hub = eventHubs.AddEventHub("orders");

// Azure Web PubSub with automatic local auth disabled  
var webPubSub = builder.AddAzureWebPubSub("webpubsub");

// Services connect using managed identity automatically
var processor = builder.AddProject<Projects.EventProcessor>("processor")
    .WithReference(hub)
    .WithReference(webPubSub);

builder.Build().Run();

この変更は、すべての Azure EventHubs および Web PubSub リソースに自動的に適用され、既定でセキュリティで保護された動作が保証されます。

🔐 Azure Key Vault 強化

Aspire 9.4 では、シークレットへの厳密に型指定されたアクセスを提供する新しいシークレット管理 API との Azure Key Vault 統合 が大幅に改善されました。

var builder = DistributedApplication.CreateBuilder(args);

var secrets = builder.AddAzureKeyVault("secrets");

// Add a secret from a parameter
var connectionStringParam = builder.AddParameter("connectionString", secret: true);
var connectionString = secrets.AddSecret("connection-string", connectionStringParam);

// Add a secret with custom secret name in Key Vault
var apiKeyParam = builder.AddParameter("api-key", secret: true);
var apiKey = secrets.AddSecret("api-key", "ApiKey", apiKeyParam);

// Get a secret reference for consumption (for existing secrets)
var existingSecret = secrets.GetSecret("ExistingSecret");

// Use in your services
var webApi = builder.AddProject<Projects.WebAPI>("webapi")
    .WithEnvironment("CONNECTION_STRING", connectionString)
    .WithEnvironment("API_KEY", apiKey)
    .WithEnvironment("EXISTING_SECRET", existingSecret);

主な機能:

  • AddSecret パラメーターまたは式から Key Vault に新しいシークレットを追加するためのメソッド
  • GetSecret Key Vault 内の既存のシークレットを参照するためのメソッド
  • 環境変数ので使用できるWithEnvironment()
  • 省略可能な パラメーターを使用したsecretNameサポート

📥リソースのディープリンクAzure Storage Queues

Aspire 9.4 では、リソースのディープ リンクが拡張され、 Azure Queue Storage キューが含まれるようになります。 Azure Blob Storage、 Cosmos DBなどに既に使用されているモデルを基に構築されます。

AppHost で個々のストレージ キューを直接モデル化し、スコープ付き QueueClient インスタンスをサービスに挿入できるようになりました。これにより、接続文字列やアクセスを手動で構成することなく、キューを簡単に操作できます。

AppHost:

var builder = DistributedApplication.CreateBuilder(args);

var storage = builder.AddAzureStorage("storage");

// Model individual queues as first-class resources
var orderQueue = storage.AddQueue("orders", "order-processing");
var notificationQueue = storage.AddQueue("notifications", "user-notifications");

// Services get scoped access to specific queues
builder.AddProject<Projects.OrderProcessor>("order-processor")
       .WithReference(orderQueue);  // Only has access to order-processing queue

builder.AddProject<Projects.NotificationService>("notifications")
       .WithReference(notificationQueue);  // Only has access to user-notifications queue

builder.Build().Run();

OrderProcessor プロジェクトで次の手順を実行します。

using Azure.Storage.Queues;

var builder = WebApplication.CreateBuilder(args);

// Register the queue client
builder.AddAzureQueue("orders");

var app = builder.Build();

// Minimal POST endpoint for image upload
app.MapPost("/process-order", async (QueueClient ordersQueue) =>
{
    // read a message for the queue
    var message = await ordersQueue.ReceiveMessageAsync();
    ProcessMessage(message);

    return Results.Ok();
});

app.Run();

この方法では、懸念事項、セキュリティで保護されたコンテナー スコープ、および最小限の処理をクリーンに分離できます。これは、特定のストレージ キューと対話するマイクロサービスに最適です。

📡 OpenTelemetry App Configuration のトレースサポートAzure

Aspire9.4 では、OpenTelemetry App Configuration のトレース機能のサポートが導入され、この統合の可観測性の完全を実現します。 Azure App Configuration 統合では、分散トレースを使用して構成取得操作と更新操作が自動的にインストルメント化されるようになりました。

var builder = WebApplication.CreateBuilder(args);

// Azure App Configuration now includes automatic tracing
builder.AddAzureAppConfiguration("config", settings =>
{
    settings.Endpoint = new Uri("https://myconfig.azconfig.io");
    // Tracing is enabled by default - traces configuration operations
});

// Optionally disable tracing for specific scenarios
builder.AddAzureAppConfiguration("sensitive-config", settings =>
{
    settings.DisableTracing = true; // Disable OpenTelemetry tracing
});

var app = builder.Build();

トレースされる内容:

  • 構成取得操作 - Azure App Configuration から構成値が読み込まれる場合
  • 構成の更新操作 - 構成がバックグラウンドで更新されたとき
  • アクティビティ ソース: Microsoft.Extensions.Configuration.AzureAppConfiguration - フィルター処理と関連付け用

機密性の高いシナリオでは、 DisableTracing = true を使用してトレースを無効にすることができます。

この機能強化により、 Azure App Configuration は、包括的な可観測性をサポートする他の Azure コンポーネントに沿って提供され、開発者は構成関連のパフォーマンスと動作に関するより優れた分析情報を得ることができます。

⚙️ 強化された Azure プロビジョニング操作

Aspire9.4 では、対話サービスを利用して、デプロイ ワークフロー中にサブスクリプションとリソース グループの構成Azure効率化することで、Azure プロビジョニング エクスペリエンスが大幅に向上します。

拡張 Azure プロビジョニング システム:

  • デプロイ操作中に、不足しているAzure構成の入力を自動的に求めるメッセージが表示される
  • 将来のデプロイメントに備えて、構成をユーザーシークレットに保存します。
  • 自動生成されたリソース グループ名などのスマートな既定値を提供します
  • サブスクリプション ID や場所などの固有の入力のAzure
  • 無料の アカウントを作成するためのリンクを含むAzureします

この機能強化により、Azureの展開が大幅に使いやすくなり、特にAzureに不慣れな開発者や初めてプロジェクトを設定する開発者にとって有用です。 対話システムにより、必要なすべての Azure 構成が対話形式で収集され、後続のデプロイ用に安全に格納されます。

🐳 Azure App Service コンテナーのサポート

Aspire 9.4 では、Dockerfile を使用してコンテナー化されたアプリケーションを App Service 環境 Azure デプロイするためのサポートが導入されています。 これにより、ローカル コンテナー開発から App Service デプロイ Azure シームレスに移行できます。

var builder = DistributedApplication.CreateBuilder(args);

// Create an Azure App Service environment
builder.AddAzureAppServiceEnvironment("app-service-env");

// Add a containerized project with Dockerfile
var containerApp = builder.AddContainer("my-app", "my-app:latest")
    .WithDockerfile("./Dockerfile");

// Or add a project that builds to a container
var webApp = builder.AddProject<Projects.WebApp>("webapp");

builder.Build().Run();

この機能は、コンテナー開発と App Service デプロイ Azure のギャップを埋め、開発者が運用環境 Azure 環境でローカルで使用するのと同じコンテナー ベースのワークフローを使用できるようにします。

🏗️ Azure Container Apps 統合の機能強化

複雑な Azure Container Apps 環境を管理するには、多くの場合、Log Analytics ワークスペースなどの既存の Azure リソースと統合する必要があります。 Aspire9.4 では、既存の リソースのサポートと構成の改善によりAzureが強化されます。

var builder = DistributedApplication.CreateBuilder(args);

// Reference existing Log Analytics workspace
var workspaceName = builder.AddParameter("workspace-name");
var workspaceRg = builder.AddParameter("workspace-rg");

var logWorkspace = builder.AddAzureLogAnalyticsWorkspace("workspace")
                          .AsExisting(workspaceName, workspaceRg);

var containerEnv = builder.AddAzureContainerAppEnvironment("production")
                          .WithAzureLogAnalyticsWorkspace(logWorkspace);

builder.AddProject<Projects.Api>("api")
       .WithComputeEnvironment(containerEnv);

builder.Build().Run();

これは、Log Analytics などの既存のリソースを再利用してコスト管理を管理するのにも役立ちます。

🛡️ ACA での .NET の DataProtection の自動構成

Aspire9.4 では、.NETにデプロイされたAzure Container Apps プロジェクトの DataProtection が自動的に構成され、1 つのインスタンスを超えてスケーリングするときにアプリケーションが正しく動作するようにします。

アプリケーション ASP.NET Core 複数のインスタンスにスケーリングする場合、すべてのインスタンスで Cookie、認証トークン、およびその他の保護されたデータを復号化するために、共有 DataProtection キーが必要です。 適切な構成がないと、ロード バランサーが要求を別のコンテナー インスタンスにルーティングするときに、認証の問題とデータの破損が発生します。

Aspireでは、Azure Container Appsにデプロイされたすべての.NETプロジェクトに対してautoConfigureDataProtectionが自動的に有効になります。

var builder = DistributedApplication.CreateBuilder(args);

builder.AddAzureContainerAppEnvironment("production");

// DataProtection is automatically configured for scaling
var api = builder.AddProject<Projects.WebApi>("api");

var frontend = builder.AddProject<Projects.BlazorApp>("frontend");

builder.Build().Run();

この機能強化により、 Aspire生成されたデプロイが Azure Developer CLI (azd) の動作に合わせて調整され、DataProtection の手動構成を必要とせずに、一般的な運用スケーリングの問題が解決されます。

⚡ Azure Functions の Container Apps との統合

Aspire 9.4 では、適切な関数アプリの種類を自動的に設定することで、 Azure Functions のデプロイが Azure Container Apps に改善されます。 これにより、 Azure Functions が適切に認識され、 Azure Container Apps 環境内で管理されます。

var builder = DistributedApplication.CreateBuilder(args);

builder.AddAzureContainerAppEnvironment("functions-env");

// Azure Functions project deployed to Container Apps
var functionsApp = builder.AddAzureFunctionsProject<Projects.MyFunctions>("functions");

builder.Build().Run();

この変更により、Container Apps にデプロイされた Azure Functions が Azure ツールと監視システムによって適切に認識されず、よりシームレスなサーバーレス エクスペリエンスが提供される問題が解決されます。

📋 プロジェクト テンプレートの機能強化

Aspire 9.4 では、 .NET 10 のサポートやファイルの名前付け規則の改善など、プロジェクト テンプレートの機能強化が導入されています。

🚀 .NET 10 個のフレームワークのサポート

すべての Aspire プロジェクト テンプレートは、フレームワーク選択が可能な .NET 10 に対応しています。 .NET 9.0 は既定のターゲット フレームワークのままです。

# Create a new Aspire project targeting .NET 10
dotnet new aspire --framework net10.0

# Create an AppHost project targeting .NET 10  
dotnet new aspire-apphost --framework net10.0

📝 ファイルの名前付け規則の改善

aspire-apphost テンプレートでは、よりわかりやすいファイルの名前付け規則が使用され、マルチプロジェクト ソリューションで AppHost ファイルを区別しやすくなります。 Program.csの代わりに、メイン プログラム ファイルに AppHost.cs という名前が付けられます。

コンテンツと機能は変更されず、ファイル名のみが更新され、よりわかりやすいものになっています。

💔 互換性を壊す変更

🔑 Azure Key Vault シークレット参照の変更

Azure Key Vault シークレット処理は、型の安全性と一貫性を向上させる改良された API で更新されました。

// ❌ Before (obsolete):
var keyVault = builder.AddAzureKeyVault("secrets");
var secretOutput = keyVault.GetSecretOutput("ApiKey");           // Obsolete
var secretRef = new BicepSecretOutputReference(secretOutput);    // Obsolete - class removed

// ✅ After (recommended):
var keyVault = builder.AddAzureKeyVault("secrets");
var secretRef = keyVault.GetSecret("ApiKey");                    // New strongly-typed API

// For environment variables:
// ❌ Before (obsolete):
builder.AddProject<Projects.Api>("api")
       .WithEnvironment("API_KEY", secretRef);  // Using BicepSecretOutputReference

// ✅ After (recommended):
builder.AddProject<Projects.Api>("api")
       .WithEnvironment("API_KEY", secretRef);  // Using IAzureKeyVaultSecretReference

移行への影響: GetSecretOutput()BicepSecretOutputReferenceの使用状況を、GetSecret()を返す新しいIAzureKeyVaultSecretReference メソッドに置き換えます。

📦 Azure ストレージ BLOB コンテナーの作成の変更

Azure 一貫性を高めるために、ストレージ BLOB コンテナーの作成が特殊な BLOB ストレージ リソースからメイン ストレージ リソースに移動されました。

// ❌ Before (obsolete):
var storage = builder.AddAzureStorage("storage");
var blobs = storage.AddBlobs("blobs");
var container = blobs.AddBlobContainer("images");     // Obsolete

// ✅ After (recommended):
var storage = builder.AddAzureStorage("storage");
var container = storage.AddBlobContainer("images");   // Direct on storage resource

移行への影響: 特殊な BLOB ストレージ リソースではなく、AddBlobContainer()で直接AzureStorageResourceを使用します。

🔐 Keycloak 領域インポートの簡略化

WithRealmImport メソッドシグネチャは、混乱を招くisReadOnlyパラメーターを削除することで簡略化されました

// ❌ Before (deprecated):
var keycloak = builder.AddKeycloak("keycloak")
    .WithRealmImport("./realm.json", isReadOnly: false);  // Confusing parameter

// ✅ After (recommended):
var keycloak = builder.AddKeycloak("keycloak")
    .WithRealmImport("./realm.json");  // Clean, simple API

// If you need explicit read-only control:
var keycloak = builder.AddKeycloak("keycloak")
    .WithRealmImport("./realm.json", isReadOnly: true);  // Still available as overload

移行への影響: 単一パラメーターisReadOnly呼び出しから WithRealmImport() パラメーターを削除します。このメソッドは既定で適切な動作になります。 明示的な制御が必要な場合は、2 パラメーターのオーバーロードを使用します。

🔧 Milvus 構成方法の更新

Milvus 構成は、よりわかりやすいメソッド名で更新されました。

// ❌ Before (deprecated):
var milvus = builder.AddMilvus("milvus")
    .WithConfigurationBindMount("./milvus.yaml");  // Old method name

// ✅ After (recommended):
var milvus = builder.AddMilvus("milvus")
    .WithConfigurationFile("./milvus.yaml");  // Method renamed for clarity

移行への影響: WithConfigurationFile構成にWithConfigurationBindMountではなく、Milvusを使用するようにメソッド呼び出しを更新します。

🔄 Azure ストレージ クライアント登録の更新

Client Azure Storage の登録方法は、新しい名前付け規則で標準化されています。

// ❌ Before (obsolete):
builder.AddAzureTableClient("tables");         // Obsolete
builder.AddKeyedAzureTableClient("tables");    // Obsolete
builder.AddAzureBlobClient("blobs");            // Obsolete
builder.AddKeyedAzureBlobClient("blobs");       // Obsolete
builder.AddAzureQueueClient("queues");          // Obsolete
builder.AddKeyedAzureQueueClient("queues");     // Obsolete

// ✅ After (recommended):
builder.AddAzureTableServiceClient("tables");         // Standardized naming
builder.AddKeyedAzureTableServiceClient("tables");    // Standardized naming
builder.AddAzureBlobServiceClient("blobs");           // Standardized naming
builder.AddKeyedAzureBlobServiceClient("blobs");      // Standardized naming
builder.AddAzureQueueServiceClient("queues");         // Standardized naming
builder.AddKeyedAzureQueueServiceClient("queues");    // Standardized naming

移行への影響: 新しい *ServiceClient 名前付け規則を使用するように、すべてのクライアント登録呼び出しを更新します。

🗄️ データベース初期化方法の変更

貫性のあるWithInitBindMountを優先して、いくつかのデータベース リソースでWithInitFilesが非推奨になりました

// ❌ Before (deprecated):
var mongo = builder.AddMongoDB("mongo")
    .WithInitBindMount("./init", isReadOnly: true);  // Complex parameters

var mysql = builder.AddMySql("mysql")  
    .WithInitBindMount("./mysql-scripts", isReadOnly: false);

var oracle = builder.AddOracle("oracle")
    .WithInitBindMount("./oracle-init", isReadOnly: true);

var postgres = builder.AddPostgres("postgres")
    .WithInitBindMount("./postgres-init", isReadOnly: true);

// ✅ After (recommended):
var mongo = builder.AddMongoDB("mongo")
    .WithInitFiles("./init");  // Simplified, consistent API

var mysql = builder.AddMySql("mysql")
    .WithInitFiles("./mysql-scripts");  // Same pattern across all providers

var oracle = builder.AddOracle("oracle")
    .WithInitFiles("./oracle-init");  // Unified approach

var postgres = builder.AddPostgres("postgres")
    .WithInitFiles("./postgres-init");  // Consistent across all databases

影響を受けるデータベース プロバイダー: MongoDB、 MySQL、 Oracle、および PostgreSQL

移行への影響: WithInitBindMount() 呼び出しを WithInitFiles() に置き換えます。新しいメソッドでは、読み取り専用のマウントが自動的に処理され、エラー処理が向上します。

リソース ライフサイクル イベントの更新

ジェネリック AfterEndpointsAllocatedEvent は、より具体的でタイプ セーフなイベントを優先して非推奨になりました。

// ❌ Before (deprecated):
builder.Services.AddSingleton<IDistributedApplicationLifecycleHook, MyLifecycleHook>();

public class MyLifecycleHook : IDistributedApplicationLifecycleHook
{
    public Task AfterEndpointsAllocatedAsync(DistributedApplicationModel appModel, CancellationToken cancellationToken)
    {
        // Generic event handling - deprecated
        return Task.CompletedTask;
    }
}

// ✅ After (recommended):
var api = builder.AddProject<Projects.Api>("api")
    .OnBeforeResourceStarted(async (resource, evt, cancellationToken) =>
    {
        // Resource-specific event handling
    })
    .OnResourceEndpointsAllocated(async (resource, evt, cancellationToken) =>
    {
        // Endpoint-specific event handling
    });

移行への影響: AfterEndpointsAllocatedEvent の使用状況を、 OnBeforeResourceStartedOnResourceEndpointsAllocated などのリソース固有のライフサイクル イベントに置き換えて、型の安全性とわかりやすくします。

🧊 ハイブリッド モードの削除Azure Container Apps

Azure Container Apps ハイブリッド モードのサポートは デプロイ モデルを簡略化し、一貫性を向上させるために削除されました。 以前は、 PublishAsAzureContainerApp は Azure インフラストラクチャを自動的に作成していましたが、この動作は合理化されています。

// ❌ Before (hybrid mode - no longer supported):
// In hybrid mode, this would automatically add Azure Container Apps infrastructure
var api = builder.AddProject<Projects.Api>("api")
    .PublishAsAzureContainerApp((infrastructure, containerApp) =>
    {
        app.Template.Scale.MinReplicas = 0;
    });

// The hybrid approach mixed azd-generated environments with Aspire-managed infrastructure
// This caused confusion and maintenance complexity

// ✅ After (required approach):
// Explicitly add Azure Container App Environment first
var containerAppEnvironment = builder.AddAzureContainerAppEnvironment("cae");

// When coming from hybrid mode, the names of the resources will change
// WithAzdResourceNaming will keep the older naming convention that azd uses
// while making this transition to aspire owned infrastructure.
containerAppEnvironment.WithAzdResourceNaming();

// Then use PublishAsAzureContainerApp for customization only (same API)
var api = builder.AddProject<Projects.Api>("api")
    .PublishAsAzureContainerApp((infrastructure, containerApp) =>
    {
        app.Template.Scale.MinReplicas = 0;
    });

主な変更:

  • PublishAsAzureContainerApp() インフラストラクチャが自動的に作成されなくなりました 。カスタマイズ注釈のみが追加されます
  • BicepSecretOutput API がAzure Container Apps ロジックから削除され、シークレット処理が簡略化されました

移行への影響:

  1. Container App Environment を明示的に追加する: 呼び出す前に を用いる
  2. シークレット参照を更新: BicepSecretOutputReference の使用を適切な Azure Key Vault リソースに IAzureKeyVaultSecretReference を使用して置き換えます。
  3. インフラストラクチャのセットアップを確認する: Bicep テンプレートまたはインフラストラクチャのセットアップによって、アプリがデプロイするコンテナー アプリ環境が適切に作成されていることを確認する

この変更により、インフラストラクチャ のプロビジョニング (明示的なリソースの作成によって処理) とアプリケーションのデプロイ構成 (によって処理) がPublishAsAzureContainerAppされ、デプロイ プロセスの予測が容易になり、理解しやすくなります。

⚠️ 既知のパラメーターの非推奨

明示的なリソース モデリングを優先して、いくつかの自動挿入された既知のパラメーターが非推奨となり、 Azure リソースから削除されました。

非推奨のパラメーター:

  • AzureBicepResource.KnownParameters.KeyVaultName
  • AzureBicepResource.KnownParameters.LogAnalyticsWorkspaceId

KeyVaultName パラメーターの非推奨

AzureBicepResource.KnownParameters.KeyVaultName パラメーターは廃止されました。 以前は、このパラメーターは、シークレットを格納するために Key Vault インスタンスを参照するために、 Azure リソースに自動的に挿入されていました。

// ❌ Before (deprecated):
var customResource = builder.AddAzureInfrastructure("custom", infra =>
{
    // Custom Bicep template that expected keyVaultName parameter to be auto-filled
    var kvNameParam = new ProvisioningParameter(AzureBicepResource.KnownParameters.KeyVaultName, typeof(string));
    infra.Add(kvNameParam);
    
    var keyVault = KeyVaultService.FromExisting("keyVault");
    keyVault.Name = kvNameParam;  // This was auto-populated by Aspire
    infra.Add(keyVault);
    
    // Store secrets in the auto-injected Key Vault
    var secret = new KeyVaultSecret("mySecret", keyVault)
    {
        Properties = { Value = "sensitive-value" }
    };
    infra.Add(secret);
});

// ✅ After (recommended):
var keyVault = builder.AddAzureKeyVault("secrets");
var customResource = builder.AddAzureInfrastructure("custom", infra =>
{
    // Use explicit Key Vault resource reference
    var existingKeyVault = (KeyVaultService)keyVault.Resource.AddAsExistingResource(infra);
    
    var secret = new KeyVaultSecret("mySecret", existingKeyVault)
    {
        Properties = { Value = "sensitive-value" }
    };
    infra.Add(secret);
});

LogAnalyticsWorkspaceId パラメーターの非推奨

AzureBicepResource.KnownParameters.LogAnalyticsWorkspaceId パラメーターは廃止されました。 Application Insights リソースは、独自の Log Analytics ワークスペースを自動的に作成するか、明示的に指定されたワークスペースを使用するようになりました。

// ❌ Before (deprecated):
var appInsights = builder.AddAzureApplicationInsights("ai")
    .WithParameter(AzureBicepResource.KnownParameters.LogAnalyticsWorkspaceId, workspaceId);

// ✅ After (recommended):
// Option 1: Auto-generated workspace (default behavior)
var appInsights = builder.AddAzureApplicationInsights("ai");

// Option 2: Explicit workspace resource
var workspace = builder.AddAzureLogAnalyticsWorkspace("workspace");
var appInsights = builder.AddAzureApplicationInsights("ai")
    .WithLogAnalyticsWorkspace(workspace);

// Option 3: Reference existing workspace from another resource
var env = builder.AddAzureContainerAppEnvironment("env");
var appInsights = builder.AddAzureApplicationInsights("ai")
    .WithLogAnalyticsWorkspace(env.GetOutput("AZURE_LOG_ANALYTICS_WORKSPACE_ID"));

コンテナーアプリ環境のパラメーター変更

以前は、コンテナー アプリ環境のプロパティ (マネージド ID、ワークスペース ID) が他の Azure リソースに自動的に挿入されていました。 これらは、Aspire が複数のコンピューティング環境をサポートするため、自動挿入されなくなりました。

// ❌ Before (auto-injection):
// These properties were automatically available in other resources:
// - MANAGED_IDENTITY_NAME
// - MANAGED_IDENTITY_PRINCIPAL_ID
// - logAnalyticsWorkspaceId

// ✅ After (explicit references):
var env = builder.AddAzureContainerAppEnvironment("env");
var resource = builder.AddAzureInfrastructure("custom", infra =>
{
    // Use explicit references when needed
    var managedEnv = (ContainerAppManagedEnvironment)env.Resource.AddAsExistingResource(infra);
    // Access properties through the bicep resource directly
});

移行への影響: 自動挿入されたパラメーターを明示的なリソース モデリングに置き換えて、リソース グラフの表現を改善し、複数の Azure コンピューティング環境をサポートします。 詳細については、Azureリソースのカスタマイズに関するドキュメントを参照してください。

🔧 ParameterResource.Value 同期動作の変更

パラメーター値の解決を待機しているときに、 ParameterResource.Value プロパティが同期的にブロックされるようになりました。これにより、非同期コンテキストでデッドロックが発生する可能性があります。 代わりに、新しい GetValueAsync() メソッドを使用して、適切な非同期処理を行う必要があります。

var builder = DistributedApplication.CreateBuilder(args);

// Parameters that need resolution
var apiKey = builder.AddParameter("api-key", secret: true);
var connectionString = builder.AddParameter("connection-string", secret: true);

// ❌ Before (can cause deadlocks in async contexts):
builder.AddProject<Projects.Api>("api")
    .WithEnvironment("API_KEY", apiKey.Resource.Value)  // Blocks synchronously - can deadlock
    .WithEnvironment("CONNECTION_STRING", connectionString.Resource.Value);

// ✅ After (recommended for async contexts):
// Use the parameter resources directly with WithEnvironment - they handle async resolution internally
builder.AddProject<Projects.Api>("api")
    .WithEnvironment("API_KEY", apiKey)  // Let Aspire handle async resolution
    .WithEnvironment("CONNECTION_STRING", connectionString);

// Or if you need the actual value in custom code with WithEnvironment callback:
builder.AddProject<Projects.Api>("api")
    .WithEnvironment("API_KEY", async (context, cancellationToken) =>
    {
        return await apiKey.Resource.GetValueAsync(cancellationToken);  // Proper async handling
    })
    .WithEnvironment("CONNECTION_STRING", async (context, cancellationToken) =>
    {
        return await connectionString.Resource.GetValueAsync(cancellationToken);
    });

// For non-async contexts where blocking is acceptable:
var syncValue = apiKey.Resource.Value;  // Still works but may block

移行への影響: 非同期コンテキストでParameterResource値を操作する場合は、GetValueAsync() プロパティの代わりに新しいValue メソッドを使用して、デッドロックの可能性を回避します。 WithEnvironment()呼び出しの場合は、.Valueに同期的にアクセスするのではなく、パラメーター リソースを直接渡すことをお勧めしています。

すべてのリリースで、 Aspire の向上に努めています。 ただし、いくつかの変更によって既存の機能が損なわれる可能性があります。 このリリースでの破壊的変更の詳細については、次を参照してください。

🎯 今すぐアップグレードする

Aspire 9.4 へのアップグレード」セクションに記載されている指示に従って、9.4 に切り替えて、これらすべての新機能を今すぐ利用してください。 いつも通り、GitHubに関するお客様のフィードバックをお待ちしており、9.5で実現してほしいことについてもお伺いしています☺️。

このリリースで対処された問題の完全な一覧については、リポジトリAspireGitHub 9.4 マイルストーンを参照してください。