-
Notifications
You must be signed in to change notification settings - Fork 349
/
AspireMicrosoftAzureCosmosExtensions.cs
140 lines (125 loc) · 6.79 KB
/
AspireMicrosoftAzureCosmosExtensions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Aspire.Hosting.Azure.Cosmos;
using Aspire.Microsoft.Azure.Cosmos;
using Azure.Identity;
using Microsoft.Azure.Cosmos;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.Extensions.Hosting;
/// <summary>
/// Azure Cosmos DB extension
/// </summary>
public static class AspireMicrosoftAzureCosmosExtensions
{
private const string DefaultConfigSectionName = "Aspire:Microsoft:Azure:Cosmos";
/// <summary>
/// Registers <see cref="CosmosClient" /> as a singleton in the services provided by the <paramref name="builder"/>.
/// Configures logging and telemetry for the <see cref="CosmosClient" />.
/// </summary>
/// <param name="builder">The <see cref="IHostApplicationBuilder" /> to read config from and add services to.</param>
/// <param name="connectionName">The connection name to use to find a connection string.</param>
/// <param name="configureSettings">An optional method that can be used for customizing the <see cref="MicrosoftAzureCosmosSettings"/>. It's invoked after the settings are read from the configuration.</param>
/// <param name="configureClientOptions">An optional method that can be used for customizing the <see cref="CosmosClientOptions"/>.</param>
/// <remarks>Reads the configuration from "Aspire:Microsoft:Azure:Cosmos" section.</remarks>
/// <exception cref="InvalidOperationException">If required ConnectionString is not provided in configuration section</exception>
public static void AddAzureCosmosClient(
this IHostApplicationBuilder builder,
string connectionName,
Action<MicrosoftAzureCosmosSettings>? configureSettings = null,
Action<CosmosClientOptions>? configureClientOptions = null)
{
AddAzureCosmosClient(builder, DefaultConfigSectionName, configureSettings, configureClientOptions, connectionName, serviceKey: null);
}
/// <summary>
/// Registers <see cref="CosmosClient" /> as a singleton for given <paramref name="name" /> in the services provided by the <paramref name="builder"/>.
/// Configures logging and telemetry for the <see cref="CosmosClient" />.
/// </summary>
/// <param name="builder">The <see cref="IHostApplicationBuilder" /> to read config from and add services to.</param>
/// <param name="name">The name of the component, which is used as the <see cref="ServiceDescriptor.ServiceKey"/> of the service and also to retrieve the connection string from the ConnectionStrings configuration section.</param>
/// <param name="configureSettings">An optional method that can be used for customizing the <see cref="MicrosoftAzureCosmosSettings"/>. It's invoked after the settings are read from the configuration.</param>
/// <param name="configureClientOptions">An optional method that can be used for customizing the <see cref="CosmosClientOptions"/>.</param>
/// <remarks>Reads the configuration from "Aspire:Microsoft:Azure:Cosmos:{name}" section.</remarks>
/// <exception cref="InvalidOperationException">If required ConnectionString is not provided in configuration section</exception>
public static void AddKeyedAzureCosmosClient(
this IHostApplicationBuilder builder,
string name,
Action<MicrosoftAzureCosmosSettings>? configureSettings = null,
Action<CosmosClientOptions>? configureClientOptions = null)
{
AddAzureCosmosClient(builder, $"{DefaultConfigSectionName}:{name}", configureSettings, configureClientOptions, connectionName: name, serviceKey: name);
}
private static void AddAzureCosmosClient(
this IHostApplicationBuilder builder,
string configurationSectionName,
Action<MicrosoftAzureCosmosSettings>? configureSettings,
Action<CosmosClientOptions>? configureClientOptions,
string connectionName,
string? serviceKey)
{
ArgumentNullException.ThrowIfNull(builder);
var settings = new MicrosoftAzureCosmosSettings();
builder.Configuration.GetSection(configurationSectionName).Bind(settings);
if (builder.Configuration.GetConnectionString(connectionName) is string connectionString)
{
if (Uri.TryCreate(connectionString, UriKind.Absolute, out var uri))
{
settings.AccountEndpoint = uri;
}
else
{
settings.ConnectionString = connectionString;
}
}
configureSettings?.Invoke(settings);
var clientOptions = new CosmosClientOptions();
// Needs to be enabled for either logging or tracing to work.
clientOptions.CosmosClientTelemetryOptions.DisableDistributedTracing = false;
if (!settings.DisableTracing)
{
builder.Services.AddOpenTelemetry().WithTracing(tracerProviderBuilder =>
{
tracerProviderBuilder.AddSource("Azure.Cosmos.Operation");
});
}
if (CosmosUtils.IsEmulatorConnectionString(settings.ConnectionString))
{
clientOptions.ConnectionMode = ConnectionMode.Gateway;
clientOptions.LimitToEndpoint = true;
}
configureClientOptions?.Invoke(clientOptions);
var cosmosApplicationName = CosmosConstants.CosmosApplicationName;
if (!string.IsNullOrEmpty(clientOptions.ApplicationName))
{
cosmosApplicationName = $"{cosmosApplicationName}/{clientOptions.ApplicationName}";
}
clientOptions.ApplicationName = cosmosApplicationName;
if (serviceKey is null)
{
builder.Services.AddSingleton(_ => ConfigureDb());
}
else
{
builder.Services.AddKeyedSingleton(serviceKey, (sp, key) => ConfigureDb());
}
CosmosClient ConfigureDb()
{
if (!string.IsNullOrEmpty(settings.ConnectionString))
{
return new CosmosClient(settings.ConnectionString, clientOptions);
}
else if (settings.AccountEndpoint is not null)
{
var credential = settings.Credential ?? new DefaultAzureCredential();
return new CosmosClient(settings.AccountEndpoint.OriginalString, credential, clientOptions);
}
else
{
throw new InvalidOperationException(
$"A CosmosClient could not be configured. Ensure valid connection information was provided in 'ConnectionStrings:{connectionName}' or either " +
$"{nameof(settings.ConnectionString)} or {nameof(settings.AccountEndpoint)} must be provided " +
$"in the '{configurationSectionName}' configuration section.");
}
}
}
}