• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

loresoft / MongoDB.Abstracts / 20140376041

11 Dec 2025 04:37PM UTC coverage: 76.38%. Remained the same
20140376041

push

github

pwelter34
framework updates

38 of 76 branches covered (50.0%)

Branch coverage included in aggregate %.

1 of 2 new or added lines in 1 file covered. (50.0%)

211 of 250 relevant lines covered (84.4%)

7.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.32
/src/MongoDB.Abstracts/ServiceCollectionExtensions.cs
1
// Ignore Spelling: Mongo
2

3
using Microsoft.Extensions.Configuration;
4
using Microsoft.Extensions.DependencyInjection;
5
using Microsoft.Extensions.DependencyInjection.Extensions;
6

7
using MongoDB.Driver;
8

9
namespace MongoDB.Abstracts;
10

11
/// <summary>
12
/// Provides extension methods for <see cref="IServiceCollection"/> to configure MongoDB repository and database services.
13
/// </summary>
14
/// <remarks>
15
/// <para>
16
/// This static class provides convenient extension methods for registering MongoDB-related services in dependency
17
/// injection containers. It supports both simple single-database scenarios and complex multi-database scenarios
18
/// using discriminator types for type-safe service resolution.
19
/// </para>
20
/// <para>
21
/// The extension methods handle connection string resolution from configuration, database instance creation,
22
/// and service registration patterns that integrate seamlessly with ASP.NET Core and other .NET applications
23
/// using Microsoft.Extensions.DependencyInjection.
24
/// </para>
25
/// <para>
26
/// All registration methods use singleton lifetime for database connections and repository services to optimize
27
/// performance and resource utilization while maintaining thread safety for concurrent operations.
28
/// </para>
29
/// </remarks>
30
public static class ServiceCollectionExtensions
31
{
32
    /// <summary>
33
    /// Registers MongoDB repository and query services with the dependency injection container using a single database connection.
34
    /// </summary>
35
    /// <param name="services">The <see cref="IServiceCollection"/> to add services to.</param>
36
    /// <param name="nameOrConnectionString">The MongoDB connection string or the name of a connection string located in the application configuration.</param>
37
    /// <returns>The same service collection so that multiple calls can be chained.</returns>
38
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> or <paramref name="nameOrConnectionString"/> is <see langword="null"/>.</exception>
39
    /// <remarks>
40
    /// <para>
41
    /// This method registers the core MongoDB repository and query services for applications using a single database.
42
    /// It automatically configures <see cref="IMongoEntityQuery{TEntity}"/> and <see cref="IMongoEntityRepository{TEntity}"/>
43
    /// services using singleton lifetime for optimal performance.
44
    /// </para>
45
    /// <para>
46
    /// The method delegates database registration to <see cref="AddMongoDatabase(IServiceCollection, string)"/> and then
47
    /// registers the generic repository and query interfaces with their concrete implementations. This provides a
48
    /// complete MongoDB data access solution with minimal configuration effort.
49
    /// </para>
50
    /// <para>
51
    /// Connection string resolution supports both direct connection strings and configuration-based lookup,
52
    /// providing flexibility for different deployment scenarios and configuration management approaches.
53
    /// </para>
54
    /// </remarks>
55
    public static IServiceCollection AddMongoRepository(this IServiceCollection services, string nameOrConnectionString)
56
    {
57
        if (services is null)
1!
58
            throw new ArgumentNullException(nameof(services));
×
59

60
        if (nameOrConnectionString is null)
1!
61
            throw new ArgumentNullException(nameof(nameOrConnectionString));
×
62

63

64
        services.AddMongoDatabase(nameOrConnectionString);
1✔
65

66
        services.TryAddSingleton(typeof(IMongoEntityQuery<>), typeof(MongoEntityQuery<>));
1✔
67
        services.TryAddSingleton(typeof(IMongoEntityRepository<>), typeof(MongoEntityRepository<>));
1✔
68

69
        return services;
1✔
70
    }
71

72
    /// <summary>
73
    /// Registers MongoDB repository and query services with discriminator support for multi-database scenarios.
74
    /// </summary>
75
    /// <typeparam name="TDiscriminator">The type used to discriminate between different MongoDB database connections.</typeparam>
76
    /// <param name="services">The <see cref="IServiceCollection"/> to add services to.</param>
77
    /// <param name="nameOrConnectionString">The MongoDB connection string or the name of a connection string located in the application configuration.</param>
78
    /// <returns>The same service collection so that multiple calls can be chained.</returns>
79
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> or <paramref name="nameOrConnectionString"/> is <see langword="null"/>.</exception>
80
    /// <remarks>
81
    /// <para>
82
    /// This method registers MongoDB repository and query services with discriminator support, enabling type-safe
83
    /// dependency injection for applications requiring multiple database connections. It configures
84
    /// <see cref="IMongoEntityQuery{TDiscriminator, TEntity}"/> and <see cref="IMongoEntityRepository{TDiscriminator, TEntity}"/>
85
    /// services with singleton lifetime for optimal performance.
86
    /// </para>
87
    /// <para>
88
    /// The discriminator pattern enables the same entity types to be used across different database contexts
89
    /// while maintaining clean separation and type safety. This is particularly useful for multi-tenant applications,
90
    /// microservices architectures, or scenarios requiring read/write replica separation.
91
    /// </para>
92
    /// <para>
93
    /// The method uses <see cref="MongoDiscriminator{TDiscriminator}"/> to wrap the database connection,
94
    /// providing the foundation for type-safe service resolution in complex application architectures.
95
    /// </para>
96
    /// </remarks>
97
    public static IServiceCollection AddMongoRepository<TDiscriminator>(this IServiceCollection services, string nameOrConnectionString)
98
    {
99
        if (services is null)
1!
100
            throw new ArgumentNullException(nameof(services));
×
101

102
        if (nameOrConnectionString is null)
1!
103
            throw new ArgumentNullException(nameof(nameOrConnectionString));
×
104

105

106
        services.AddMongoDatabase<TDiscriminator>(nameOrConnectionString);
1✔
107

108
        services.TryAddSingleton(typeof(IMongoEntityQuery<,>), typeof(MongoEntityQuery<,>));
1✔
109
        services.TryAddSingleton(typeof(IMongoEntityRepository<,>), typeof(MongoEntityRepository<,>));
1✔
110

111
        return services;
1✔
112
    }
113

114
    /// <summary>
115
    /// Registers a MongoDB database service with the dependency injection container for single-database scenarios.
116
    /// </summary>
117
    /// <param name="services">The <see cref="IServiceCollection"/> to add services to.</param>
118
    /// <param name="nameOrConnectionString">The MongoDB connection string or the name of a connection string located in the application configuration.</param>
119
    /// <returns>The same service collection so that multiple calls can be chained.</returns>
120
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> or <paramref name="nameOrConnectionString"/> is <see langword="null"/>.</exception>
121
    /// <remarks>
122
    /// <para>
123
    /// This method registers an <see cref="IMongoDatabase"/> service as a singleton, providing a shared database
124
    /// connection for all MongoDB operations in the application. The database instance is created using the
125
    /// <see cref="MongoFactory"/> utility with proper connection string resolution.
126
    /// </para>
127
    /// <para>
128
    /// Connection string resolution is handled automatically, supporting both direct connection strings and
129
    /// configuration-based lookup through the application's <see cref="IConfiguration"/> service. This provides
130
    /// flexibility for different deployment scenarios and configuration management approaches.
131
    /// </para>
132
    /// <para>
133
    /// The singleton lifetime ensures optimal resource utilization and performance while maintaining thread safety
134
    /// for concurrent database operations across the application.
135
    /// </para>
136
    /// </remarks>
137
    public static IServiceCollection AddMongoDatabase(this IServiceCollection services, string nameOrConnectionString)
138
    {
139
        if (services is null)
1!
140
            throw new ArgumentNullException(nameof(services));
×
141

142
        if (nameOrConnectionString is null)
1!
143
            throw new ArgumentNullException(nameof(nameOrConnectionString));
×
144

145
        services.TryAddSingleton(sp =>
1✔
146
        {
1✔
147
            var connectionString = ResolveConnectionString(sp, nameOrConnectionString);
1✔
148
            return MongoFactory.GetDatabaseFromConnectionString(connectionString);
1✔
149
        });
1✔
150

151
        return services;
1✔
152
    }
153

154
    /// <summary>
155
    /// Registers a MongoDB database service with discriminator support for multi-database scenarios.
156
    /// </summary>
157
    /// <typeparam name="TDiscriminator">The type used to discriminate between different MongoDB database connections.</typeparam>
158
    /// <param name="services">The <see cref="IServiceCollection"/> to add services to.</param>
159
    /// <param name="nameOrConnectionString">The MongoDB connection string or the name of a connection string located in the application configuration.</param>
160
    /// <returns>The same service collection so that multiple calls can be chained.</returns>
161
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> or <paramref name="nameOrConnectionString"/> is <see langword="null"/>.</exception>
162
    /// <remarks>
163
    /// <para>
164
    /// This method registers a <see cref="MongoDiscriminator{TDiscriminator}"/> service as a singleton, wrapping
165
    /// the MongoDB database connection with type-safe discriminator support. This enables multiple database
166
    /// connections to be registered and resolved independently using different discriminator types.
167
    /// </para>
168
    /// <para>
169
    /// The discriminator pattern provides compile-time type safety for dependency injection scenarios where
170
    /// multiple database connections are required. Each discriminator type represents a distinct database
171
    /// context, enabling clean separation of multi-tenant data, read/write replicas, or domain-specific databases.
172
    /// </para>
173
    /// <para>
174
    /// Connection string resolution and database creation follow the same patterns as single-database scenarios,
175
    /// with the additional discriminator wrapper providing the foundation for type-safe multi-connection support.
176
    /// </para>
177
    /// </remarks>
178
    public static IServiceCollection AddMongoDatabase<TDiscriminator>(this IServiceCollection services, string nameOrConnectionString)
179
    {
180
        if (services is null)
1!
181
            throw new ArgumentNullException(nameof(services));
×
182

183
        if (nameOrConnectionString is null)
1!
184
            throw new ArgumentNullException(nameof(nameOrConnectionString));
×
185

186

187
        services.TryAddSingleton(sp =>
1✔
188
        {
1✔
189
            var connectionString = ResolveConnectionString(sp, nameOrConnectionString);
1✔
190
            var database = MongoFactory.GetDatabaseFromConnectionString(connectionString);
1✔
191

1✔
192
            return new MongoDiscriminator<TDiscriminator>(database);
1✔
193
        });
1✔
194

195
        return services;
1✔
196
    }
197

198
    /// <summary>
199
    /// Registers a MongoDB database service with a specific service key for keyed service scenarios.
200
    /// </summary>
201
    /// <param name="services">The <see cref="IServiceCollection"/> to add services to.</param>
202
    /// <param name="nameOrConnectionString">The MongoDB connection string or the name of a connection string located in the application configuration.</param>
203
    /// <param name="serviceKey">The service key used for keyed service registration and resolution.</param>
204
    /// <returns>The same service collection so that multiple calls can be chained.</returns>
205
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> or <paramref name="nameOrConnectionString"/> is <see langword="null"/>.</exception>
206
    /// <remarks>
207
    /// <para>
208
    /// This method registers an <see cref="IMongoDatabase"/> service using keyed service registration, enabling
209
    /// multiple database connections to be registered and resolved using different service keys. This approach
210
    /// is useful for scenarios where string-based or object-based keys provide more flexibility than type-based discrimination.
211
    /// </para>
212
    /// <para>
213
    /// Keyed services provide an alternative to discriminator types for multi-database scenarios, offering
214
    /// runtime-based service resolution using keys rather than compile-time type safety. This can be useful
215
    /// for dynamic configuration scenarios or when database selection depends on runtime conditions.
216
    /// </para>
217
    /// <para>
218
    /// The service key can be any object type, providing flexibility for different keying strategies including
219
    /// strings, enums, or custom key objects. Connection string resolution follows standard patterns with
220
    /// automatic configuration lookup support.
221
    /// </para>
222
    /// </remarks>
223
    public static IServiceCollection AddMongoDatabase(this IServiceCollection services, string nameOrConnectionString, object? serviceKey)
224
    {
225
        if (services is null)
1!
226
            throw new ArgumentNullException(nameof(services));
×
227

228
        if (nameOrConnectionString is null)
1!
229
            throw new ArgumentNullException(nameof(nameOrConnectionString));
×
230

231
        services.TryAddKeyedSingleton(
1✔
232
            serviceKey: serviceKey,
1✔
233
            implementationFactory: (sp, key) =>
1✔
234
            {
1✔
235
                var connectionString = ResolveConnectionString(sp, nameOrConnectionString);
1✔
236
                return MongoFactory.GetDatabaseFromConnectionString(connectionString);
1✔
237
            }
1✔
238
        );
1✔
239

240
        return services;
1✔
241
    }
242

243
    /// <summary>
244
    /// Resolves a connection string from either a direct connection string or a configuration key name.
245
    /// </summary>
246
    /// <param name="services">The <see cref="IServiceProvider"/> used to access configuration services.</param>
247
    /// <param name="nameOrConnectionString">The connection string value or the name of a connection string located in the application configuration.</param>
248
    /// <returns>The resolved MongoDB connection string ready for use with MongoDB driver.</returns>
249
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> is <see langword="null"/>.</exception>
250
    /// <remarks>
251
    /// <para>
252
    /// This method provides intelligent connection string resolution by first attempting to detect if the provided
253
    /// value is a direct connection string (by checking for common connection string characters) or a configuration key name.
254
    /// If it appears to be a direct connection string, it is returned unchanged.
255
    /// </para>
256
    /// <para>
257
    /// For configuration-based resolution, the method first attempts to resolve the value from the standard
258
    /// ConnectionStrings configuration section, then falls back to searching the root configuration collection.
259
    /// This provides flexibility for different configuration organization approaches.
260
    /// </para>
261
    /// <para>
262
    /// If no configuration value is found, the original input is returned as-is, providing a fallback that
263
    /// supports direct connection string usage even when configuration lookup fails. This ensures robust
264
    /// behavior across different deployment and configuration scenarios.
265
    /// </para>
266
    /// </remarks>
267
    public static string ResolveConnectionString(this IServiceProvider services, string nameOrConnectionString)
268
    {
269
        var isConnectionString = nameOrConnectionString.IndexOfAny([';', '=', ':', '/']) > 0;
3✔
270
        if (isConnectionString)
3✔
271
            return nameOrConnectionString;
2✔
272

273
        var configuration = services.GetRequiredService<IConfiguration>();
1✔
274

275
        // first try connection strings section
276
        var connectionString = configuration.GetConnectionString(nameOrConnectionString);
1✔
277
        if (!string.IsNullOrEmpty(connectionString))
1!
278
            return connectionString!;
1✔
279

280
        // next try root collection
281
        connectionString = configuration[nameOrConnectionString];
×
282
        if (!string.IsNullOrEmpty(connectionString))
×
NEW
283
            return connectionString!;
×
284

285
        return nameOrConnectionString;
×
286
    }
287
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc