1

So I'm building an ASP.NET-Core API connecting to a mongoDB instance. I was reading through the official Microsoft tutorial regarding this topic and came across the linked code sample.

Basically they instantiate a BookService and create a new instance of MongoClient in the scope of the constructor.

private readonly IMongoCollection<Book> _books;

public BookService(IBookstoreDatabaseSettings settings)
{
    var client = new MongoClient(settings.ConnectionString);
    var database = client.GetDatabase(settings.DatabaseName);
    _books = database.GetCollection<Book>(settings.BooksCollectionName);
}

As I understand this the _books collection would still work without the MongoClient instance present since it knows which collection it's assigned to and how to communicate with it BUT the mongoDB MongoClient re-use guidelines suggests to store a global/static instance of the client to re-use. (I guess for the same port-exhaustion, etc. reason you would want to re-use HTTPClients? Also it supports internal connection pooling, which is nice!)

Thinking further on what they imply I was quite sure it would be a bad idea to instantiate and immediately drop an instance for a client for each of my services. But I dont't know anything about MongoDB on this scope.

I know it's just a tutorial and they tend to be the "quick and dirty" way of coding but since I'm new to this whole topic I just wanted to make sure I would start out properly.

So is it OK doing it the "Microsoft way" or should I just create a global instance for the client or a factory altogether?

//Edit:

For clarification: Would it be better to register the MongoClient as a Singleton on Startup and inject it into classes that need it OR use the method described above?

Nicolas
  • 440
  • 4
  • 13
  • 2
    Does this answer your question? [mongodb service - singleton or scoped?](https://stackoverflow.com/questions/59599151/mongodb-service-singleton-or-scoped) – Liam Mar 19 '21 at 10:54
  • 1
    Yes, it does! Thank you! – Nicolas Jul 27 '21 at 12:32

1 Answers1

4

This is how I typically add Mongo to my pipelines:

services.AddSingleton<IMongoClient>(sp =>
{ 
    var connectionString = "";
    return new MongoClient(connectionString);
});
services.AddScoped(sp =>
{
    var client = sp.GetRequiredService<IMongoClient>();
    var database = "";
    return client.GetDatabase(database);
});

This gives me a scoped IDatabase instance I can inject anywhere I need it (while using just one singleton IMongoClient instance).

crgolden
  • 4,332
  • 1
  • 22
  • 40
  • That looks nice! I might try that. Thank you! – Nicolas Aug 07 '20 at 18:16
  • could you please elaborate on that? What advantages does your pipeline have compared to simple ```var client = new MongoClient(connectionStr); services.AddScoped(_ => client.GetDatabase(dbName):``` ? – Nikita Fedorov Nov 30 '20 at 15:21
  • @Nikita Fedorov The advantage is that you can still access a singleton instance of `IMongoClient` anywhere else in your application (if you ever need to). – crgolden Nov 30 '20 at 19:12
  • The Mongo documentation says that the connection settings (i.e. connection string, database name, and collection name) must be the same between classes wherever IMongoClient is injected in order to utilize Mongo's native pooling. " It is recommended to store a MongoClient instance in a global place, either as a static variable or in an IoC container with a singleton lifetime. However, multiple MongoClient instances created with the same settings will utilize the same connection pools underneath." – Brandon Harmon Jul 22 '23 at 00:36