GSoft.Extensions.Mongo.Ephemeral 1.3.0

Prefix Reserved
Suggested Alternatives

Workleap.Extensions.Mongo.Ephemeral

dotnet add package GSoft.Extensions.Mongo.Ephemeral --version 1.3.0                
NuGet\Install-Package GSoft.Extensions.Mongo.Ephemeral -Version 1.3.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="GSoft.Extensions.Mongo.Ephemeral" Version="1.3.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add GSoft.Extensions.Mongo.Ephemeral --version 1.3.0                
#r "nuget: GSoft.Extensions.Mongo.Ephemeral, 1.3.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install GSoft.Extensions.Mongo.Ephemeral as a Cake Addin
#addin nuget:?package=GSoft.Extensions.Mongo.Ephemeral&version=1.3.0

// Install GSoft.Extensions.Mongo.Ephemeral as a Cake Tool
#tool nuget:?package=GSoft.Extensions.Mongo.Ephemeral&version=1.3.0                

GSoft.Extensions.Mongo

nuget build

Provides MongoDB access through .NET dependency injection, following Microsoft.Extensions.* library practices with several features:

  • Automatic indexes creation, update and removal based on code changes
  • Encryption at field level with different scopes (per user, tenant, or application-wide)
  • Dependency-injection enabled using IServiceCollection and IServiceProvider
  • Highly configurable (custom serializers, conventions, multiple databases support)
  • Support for multiple MongoDB connection strings and MongoDB clients
  • Roslyn analyzers for increased awareness of index usage
  • IAsyncEnumerable support

Getting started

Install the package GSoft.Extensions.Mongo.Abstractions in the project where you'll declare your documents. This package contains base classes and interfaces such as IMongoDocument, MongoIndexProvider, MongoCollectionAttribute. There's also a few extension methods of the MongoDB C# driver classes and interfaces that adds IAsyncEnumerable support to cursors.

Install the package GSoft.Extensions.Mongo at the application entry point level to register and configure the dependencies in a IServiceCollection.

Install the package GSoft.Extensions.Mongo.Ephemeral whenever you want to use a real but ephemeral MongoDB cluster with a single node replica set. This is ideal for integration testing, as each IServiceProvider will have access to an unique and isolated database.

Example

// In the project that contains the documents:
// 1) Declare the collection name (camelCase) and the type responsible for providing indexes (optional)
[MongoCollection("people", IndexProviderType = typeof(PersonDocumentIndexes))]
public class PersonDocument : IMongoDocument
{
    [BsonId]
    [BsonRepresentation(BsonType.ObjectId)]
    public string Id { get; set; }

    public string Name { get; set; } = string.Empty;
}

public class PersonDocumentIndexes : MongoIndexProvider<PersonDocument>
{
    public override IEnumerable<CreateIndexModel<PersonDocument>> CreateIndexModels()
    {
        // Index name is mandatory
        yield return new CreateIndexModel<PersonDocument>(
            Builders<PersonDocument>.IndexKeys.Combine().Ascending(x => x.Name),
            new CreateIndexOptions { Name = "name" });
    }
}
// 2) In the project that configures the application:
var services = new ServiceCollection();
services
    .AddMongo(ConfigureDefaultMongoClient) // <-- register the default MongoDB client and database
    .AddNamedClient("anotherClient", ConfigureAnotherMongoClient) // <-- (optional) register multiple MongoDB clients with different options and connection strings
    .AddEncryptor<YourMongoValueEncryptor>() // (optional) <-- specify how to encrypt sensitive fields
    .ConfigureStaticOptions(ConfigureMongoStatic); // (optional) <-- specify MongoDB C# driver static settings

private static void ConfigureDefaultMongoClient(MongoClientOptions options)
{
    // Simplified for demo purposes, it is better to use appsettings.json, secret vaults
    // and IConfigureOptions<> classes that can use dependency injection to access other options or dependencies
    options.ConnectionString = "mongodb://localhost";
    options.DefaultDatabaseName = "default";
    options.EnableSensitiveInformationLogging = true;

    // Used by the automatic index update feature
    options.Indexing.LockMaxLifetimeInSeconds = 300;
    options.Indexing.LockAcquisitionTimeoutInSeconds = 60;

    // Modify MongoClientSettings (optional)
    options.MongoClientSettingsConfigurator = settings => { };
    
    // EXPERIMENTAL, FOR LOCAL DEVELOPMENT ONLY:
    // This will output a warning log when a collection scan is detected on a "find" command
    options.CommandPerformanceAnalysis.EnableCollectionScanDetection = true;
}

private static void ConfigureAnotherMongoClient(MongoClientOptions options)
{
    // Define options relative to this non-default MongoDB client
    // Ideally, use IConfigureNamedOptions<MongoClientOptions>
}

private static void ConfigureMongoStatic(MongoStaticOptions options)
{    
    // There are built-in serializers and conventions registered, but you can remove or override them
    // ⚠ Careful, these are objects that will live for the entire lifetime of the application (singleton) as MongoDB C# driver
    // uses static properties to configure its behavior and serialization
    options.BsonSerializers[typeof(Foo)] = new MyFooBsonSerializer();
    options.ConventionPacks.Add(new MyConventionPack());
}

// MongoDB document properties can be encrypted when decorated with the [SensitiveInformation(scope)] attribute
// There is a convention pack that use this class to encrypt and decrypt values using a custom BsonSerializer.
// This is not required if you never use the attribute.
private sealed class YourMongoValueEncryptor : IMongoValueEncryptor
{
    // Encrypt and decrypt the bytes based on the sensitivity scope
    // Use AsyncLocal<> to determine if the sensitivity scopes matches the current execution context.
    // For instance, SensitivityScope.User should only work if there is actually an authenticated user detected through IHttpContextAccessor,
    // or any other ambient mechanism that relies on AsyncLocal<>.
    public byte[] Encrypt(byte[] bytes, SensitivityScope sensitivityScope) => bytes;
    public byte[] Decrypt(byte[] bytes, SensitivityScope sensitivityScope) => bytes;
}
// 3) Consume the registered services
// Automatically update indexes if their definition in the code has changed - a cryptographic hash is used to detect changes.
// There's a distributed lock that prevents race conditions.
// UpdateIndexesAsync() also accepts an optional registered MongoDB client name, database name and/or cancellation token. 
var indexer = this.Services.GetRequiredService<IMongoIndexer>();
await indexer.UpdateIndexesAsync(new[] { typeof(PersonDocument) });
await indexer.UpdateIndexesAsync(new[] { typeof(PersonDocument).Assembly }); // Assembly scanning alternative

// No need to know the collection name, just use the document type which must be decorated with MongoCollectionAttribute
var collection = this.Services.GetRequiredService<IMongoCollection<PersonDocument>>();
// OR: var collection = this.Services.GetRequiredService<IMongoDatabase>().GetCollection<PersonDocument>();

// No cursors handling needed, use IAsyncEnumerable
var people = await collection.Find(FilterDefinition<PersonDocument>.Empty).ToAsyncEnumerable();

// Access other registered MongoDB clients
var anotherMongoClient = this.Services.GetRequiredService<IMongoClientProvider>().GetClient("anotherClient");
// 4) Add the GSoft.Extensions.Mongo.Ephemeral package to use a ephemeral but real MongoDB database in your tests
var services = new ServiceCollection();
services.AddMongo().UseEphemeralRealServer();

Included Roslyn analyzers

Rule ID Category Severity Description
GMNG01 Design Warning Add 'IndexBy' or 'NoIndexNeeded' attributes on the containing type

In order to change the severity of one of these diagnostic rules, use a .editorconfig file, for instance:

## Disable analyzer for test files
[**Tests*/**.cs]
dotnet_diagnostic.GMNG01.severity = none

To learn more about how to configure or suppress code analysis warnings, read this documentation.

License

Copyright © 2023, GSoft Group Inc. This code is licensed under the Apache License, Version 2.0. You may obtain a copy of this license at https://github.com/gsoft-inc/gsoft-license/blob/master/LICENSE.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 is compatible.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.