|
5 | 5 | using Microsoft.Extensions.Configuration; |
6 | 6 | using Microsoft.Extensions.DependencyInjection; |
7 | 7 | using Microsoft.SemanticKernel; |
| 8 | +using Npgsql; |
8 | 9 |
|
9 | 10 | namespace EssentialCSharp.Chat.Common.Extensions; |
10 | 11 |
|
11 | 12 | public static class ServiceCollectionExtensions |
12 | 13 | { |
| 14 | + private static readonly string[] PostgresScopes = ["https://ossrdbms-aad.database.windows.net/.default"]; |
| 15 | + |
13 | 16 | /// <summary> |
14 | 17 | /// Adds Azure OpenAI and related AI services to the service collection using Managed Identity |
15 | 18 | /// </summary> |
@@ -50,8 +53,8 @@ public static IServiceCollection AddAzureOpenAIServices( |
50 | 53 | aiOptions.Endpoint, |
51 | 54 | credential); |
52 | 55 |
|
53 | | - // Add PostgreSQL vector store |
54 | | - services.AddPostgresVectorStore(postgresConnectionString); |
| 56 | + // Add PostgreSQL vector store with managed identity support |
| 57 | + services.AddPostgresVectorStoreWithManagedIdentity(postgresConnectionString, credential); |
55 | 58 |
|
56 | 59 | services.AddAzureOpenAIEmbeddingGenerator( |
57 | 60 | aiOptions.VectorGenerationDeploymentName, |
@@ -96,6 +99,55 @@ public static IServiceCollection AddAzureOpenAIServices( |
96 | 99 | return services.AddAzureOpenAIServices(aiOptions, postgresConnectionString, credential); |
97 | 100 | } |
98 | 101 |
|
| 102 | + /// <summary> |
| 103 | + /// Adds PostgreSQL vector store with managed identity authentication support. |
| 104 | + /// NOTE: Token is obtained once at startup and will expire after ~1 hour. |
| 105 | + /// For long-running applications, consider restarting the application periodically |
| 106 | + /// or implementing a background service to refresh the connection. |
| 107 | + /// </summary> |
| 108 | + /// <param name="services">The service collection to add services to</param> |
| 109 | + /// <param name="connectionString">The PostgreSQL connection string (without password)</param> |
| 110 | + /// <param name="credential">The token credential to use for authentication. If null, DefaultAzureCredential will be used.</param> |
| 111 | + /// <returns>The service collection for chaining</returns> |
| 112 | + private static IServiceCollection AddPostgresVectorStoreWithManagedIdentity( |
| 113 | + this IServiceCollection services, |
| 114 | + string connectionString, |
| 115 | + TokenCredential? credential = null) |
| 116 | + { |
| 117 | + credential ??= new DefaultAzureCredential(); |
| 118 | + |
| 119 | + // Parse the connection string to extract host, database, and username |
| 120 | + var builder = new NpgsqlConnectionStringBuilder(connectionString); |
| 121 | + |
| 122 | + // Check if this is an Azure PostgreSQL connection (contains .postgres.database.azure.com) |
| 123 | + bool isAzurePostgres = builder.Host?.Contains(".postgres.database.azure.com", StringComparison.OrdinalIgnoreCase) ?? false; |
| 124 | + |
| 125 | + if (isAzurePostgres && string.IsNullOrEmpty(builder.Password)) |
| 126 | + { |
| 127 | + // Get access token for Azure PostgreSQL using managed identity |
| 128 | + var tokenRequestContext = new TokenRequestContext(PostgresScopes); |
| 129 | + var accessToken = credential.GetToken(tokenRequestContext, default); |
| 130 | + |
| 131 | + // Set the password to the access token |
| 132 | + builder.Password = accessToken.Token; |
| 133 | + |
| 134 | + // Ensure SSL is enabled for Azure |
| 135 | + if (builder.SslMode == SslMode.Disable) |
| 136 | + { |
| 137 | + builder.SslMode = SslMode.Require; |
| 138 | + } |
| 139 | + |
| 140 | + connectionString = builder.ToString(); |
| 141 | + } |
| 142 | + |
| 143 | + // Register the vector store using the connection string |
| 144 | +#pragma warning disable SKEXP0010 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. |
| 145 | + services.AddPostgresVectorStore(connectionString); |
| 146 | +#pragma warning restore SKEXP0010 |
| 147 | + |
| 148 | + return services; |
| 149 | + } |
| 150 | + |
99 | 151 | /// <summary> |
100 | 152 | /// Adds Azure OpenAI and related AI services to the service collection using API key authentication (legacy) |
101 | 153 | /// </summary> |
@@ -138,7 +190,7 @@ public static IServiceCollection AddAzureOpenAIServicesWithApiKey( |
138 | 190 | aiOptions.Endpoint, |
139 | 191 | apiKey); |
140 | 192 |
|
141 | | - // Add PostgreSQL vector store |
| 193 | + // Add PostgreSQL vector store (standard connection string with password) |
142 | 194 | services.AddPostgresVectorStore(postgresConnectionString); |
143 | 195 |
|
144 | 196 | services.AddAzureOpenAIEmbeddingGenerator( |
|
0 commit comments