| File: AspireAzureAIProjectsExtensions.cs | Web Access |
| Project: src\src\Components\Aspire.Azure.AI.Projects\Aspire.Azure.AI.Projects.csproj (Aspire.Azure.AI.Projects) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Aspire; using Aspire.Azure.AI.Projects; using Aspire.Azure.Common; using Azure.AI.Projects; using Azure.Core; using Azure.Core.Extensions; using Microsoft.Extensions.Azure; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Diagnostics.HealthChecks; namespace Microsoft.Extensions.Hosting; /// <summary> /// Provides extension methods for registering Azure AI Projects clients with configuration and tracing. /// </summary> public static class AspireAzureAIProjectsExtensions { internal const string DefaultConfigSectionName = "Aspire:Azure:AI:Projects"; /// <summary> /// Registers <see cref="AIProjectClient"/> as a singleton using Microsoft Entra authentication. /// </summary> /// <param name="builder">The application builder.</param> /// <param name="connectionName">The name of the project connection string.</param> /// <param name="configureSettings">Customizes settings after configuration and connection-string binding.</param> /// <param name="configureClientBuilder">Customizes the Azure client registration and options.</param> /// <remarks>Reads configuration from <c>Aspire:Azure:AI:Projects</c> and its connection-specific subsection.</remarks> /// <example> /// <code> /// builder.AddAzureAIProjectClient("project"); /// </code> /// </example> /// <exception cref="ArgumentNullException"><paramref name="builder"/> is null.</exception> /// <exception cref="ArgumentException"><paramref name="connectionName"/> is null or empty, or the connection string is invalid.</exception> public static void AddAzureAIProjectClient( this IHostApplicationBuilder builder, string connectionName, Action<AzureAIProjectsSettings>? configureSettings = null, Action<IAzureClientBuilder<AIProjectClient, AIProjectClientOptions>>? configureClientBuilder = null) { ArgumentNullException.ThrowIfNull(builder); ArgumentException.ThrowIfNullOrEmpty(connectionName); new ProjectsComponent().AddClient(builder, DefaultConfigSectionName, configureSettings, configureClientBuilder, connectionName, serviceKey: null); } /// <summary> /// Registers <see cref="AIProjectClient"/> as a keyed singleton using Microsoft Entra authentication. /// </summary> /// <param name="builder">The application builder.</param> /// <param name="name">The service key and project connection-string name.</param> /// <param name="configureSettings">Customizes settings after configuration and connection-string binding.</param> /// <param name="configureClientBuilder">Customizes the Azure client registration and options.</param> /// <remarks>Uses <paramref name="name"/> for both configuration lookup and keyed service resolution.</remarks> /// <example> /// <code> /// builder.AddKeyedAzureAIProjectClient("project"); /// </code> /// </example> /// <exception cref="ArgumentNullException"><paramref name="builder"/> is null.</exception> /// <exception cref="ArgumentException"><paramref name="name"/> is null or empty, or the connection string is invalid.</exception> public static void AddKeyedAzureAIProjectClient( this IHostApplicationBuilder builder, string name, Action<AzureAIProjectsSettings>? configureSettings = null, Action<IAzureClientBuilder<AIProjectClient, AIProjectClientOptions>>? configureClientBuilder = null) { ArgumentNullException.ThrowIfNull(builder); ArgumentException.ThrowIfNullOrEmpty(name); new ProjectsComponent().AddClient(builder, DefaultConfigSectionName, configureSettings, configureClientBuilder, name, serviceKey: name); } private sealed class ProjectsComponent : AzureComponent<AzureAIProjectsSettings, AIProjectClient, AIProjectClientOptions> { protected override IAzureClientBuilder<AIProjectClient, AIProjectClientOptions> AddClient( AzureClientFactoryBuilder azureFactoryBuilder, AzureAIProjectsSettings settings, string connectionName, string configurationSectionName) { return azureFactoryBuilder.AddClient<AIProjectClient, AIProjectClientOptions>((options, credential, _) => { if (settings.Endpoint is null) { throw new InvalidOperationException($"An AIProjectClient could not be configured. Provide 'ConnectionStrings:{connectionName}' or an Endpoint in '{configurationSectionName}'."); } return new AIProjectClient(AzureAIProjectConnectionString.ValidateEndpoint(settings.Endpoint), credential, options); }); } protected override void BindSettingsToConfiguration(AzureAIProjectsSettings settings, IConfiguration configuration) => configuration.Bind(settings); protected override void BindClientOptionsToConfiguration(IAzureClientBuilder<AIProjectClient, AIProjectClientOptions> clientBuilder, IConfiguration configuration) { #pragma warning disable IDE0200 // The configuration binding source generator requires a lambda. clientBuilder.ConfigureOptions(options => configuration.Bind(options)); #pragma warning restore IDE0200 } // No permission-independent, inference-free health endpoint is available for project clients. protected override bool GetHealthCheckEnabled(AzureAIProjectsSettings settings) => false; protected override IHealthCheck CreateHealthCheck(AIProjectClient client, AzureAIProjectsSettings settings) => throw new NotSupportedException("Health checks are not supported for AIProjectClient."); protected override bool GetMetricsEnabled(AzureAIProjectsSettings settings) => false; protected override bool GetTracingEnabled(AzureAIProjectsSettings settings) => !settings.DisableTracing; protected override TokenCredential? GetTokenCredential(AzureAIProjectsSettings settings) => settings.Credential ?? AzureCredentialHelper.CreateDefaultAzureCredential(); } }