I am building an API with ASP.NET core using Mongodb and i have different services user service home service and etc. I would like to know should i register every service as singleton as it is mentioned in asp.net core documention or as scoped. Link to repository https://github.com/krisk0su/apartments
UserService.cs
public class UserService
{
private readonly IMongoCollection<User> _books;
private readonly IPasswordHasher _passwordService;
public UserService(IBookstoreDatabaseSettings settings, IPasswordHasher passwordService)
{
var client = new MongoClient(settings.ConnectionString);
var database = client.GetDatabase(settings.DatabaseName);
_books = database.GetCollection<User>(settings.UsersCollectionName);
_passwordService = passwordService;
}
public List<User> Get() =>
_books
.Find(book => true)
.ToList();
public User Get(string id) =>
_books.Find(user => user.Id == id).FirstOrDefault();
public User Create(User user)
{
var password = this._passwordService.HashPassword(user.Password);
user.Password = password;
_books.InsertOne(user);
return user;
}
public void Update(string id, User bookIn) =>
_books.ReplaceOne(book => book.Id == id, bookIn);
public void Remove(User bookIn) =>
_books.DeleteOne(book => book.Id == bookIn.Id);
public void Remove(string id) =>
_books.DeleteOne(book => book.Id == id);
}
Startup.cs
services.AddSingleton<UserService>();
services.AddSingleton<BookService>();
services.AddSingleton<AuthenticationService>();
services.AddScoped<IPasswordHasher, PasswordHasher>();
Typically yes, it is a good practice to make MongoClient a singleton. As mentioned in the MongoDB Java driver: The MongoClient instance represents a pool of connections to the database; you will only need one instance of class MongoClient even with multiple threads.
Connect to a Replica Setconst MongoClient = require('mongodb'). MongoClient; const assert = require('assert'); // Connection URL const url = 'mongodb://localhost:27017,localhost:27018/?replicaSet=foo'; // Database Name const dbName = 'myproject'; // Use connect method to connect to the Server MongoClient.
The MongoClient class is a class that allows for making Connections to MongoDB. remarks. The programmatically provided options take precedence over the URI options. example // Connect using a MongoClient instance const MongoClient = require('mongodb').
Well its complicated.
First of all MongoClient
can be singleton, so all services that uses MongoClient
can be singletons as well. Its important cause singleton service cannot depends on service with shorter life (Scoped, Transient).
Now about UserService
. All its dependancies is singletons and service itself don't stores any data (no fields, no props) that should live limited time or any data about particular user etc.
So it can be singleton!
But if you decided to add scoped dependancy or store any data in it:
public class UserService
{
private readonly IMongoCollection<User> users;
private readonly long userCount; //this one
public UserService(IBookstoreDatabaseSettings settings)
{
var client = new MongoClient(settings.ConnectionString);
var database = client.GetDatabase(settings.DatabaseName);
users = database.GetCollection<User>(settings.UsersCollectionName);
userCount = users.Find(_ => true).CountDocuments();
}
}
then you have to make it at least Scoped.
Btw it's much easier to have MongoClient
as singleton in DI:
services.AddSingleton<IMongoClient>(s =>
new MongoClient(Configuration.GetConnectionString("MongoDb"))
);
and then use it in all services:
public class UserService
{
private readonly IMongoCollection<User> users;
public UserService(IMongoClient mongoClient)
{
var database = mongoClient.GetDatabase("DatabaseName");
users = database.GetCollection<User>(settings.UsersCollectionName);
}
}
Or if you will use just one database in your app you can move IMongoDatabase to DI as well and then you don’t need to get it every time in the service constructor.
The MongoDB .NET Driver reference documentation for version 2.17 explains on the Reference > Driver > Connecting page in the Mongo Client Re-use section that:
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.
With regards to Mongo Database Re-use it doesn't mention a singleton lifetime but it does say it "is thread-safe and is safe to be stored globally", so I would interpret that to mean it can be stored safely as a singleton if that's what your implementation desired, but it doesn't need to be if you prefer another lifetime.
The implementation of
IMongoDatabase
provided by aMongoClient
is thread-safe and is safe to be stored globally or in an IoC container.
It's the same with regards to Mongo Collection Re-use:
The implementation of
IMongoCollection<TDocument>
ultimately provided by aMongoClient
is thread-safe and is safe to be stored globally or in an IoC container.
So again I'd interpret that to mean the choice of lifetime is up to your specific requirements.
It seems it's only the MongoClient
that carries a recommendation to use a singleton lifetime.
Thank you for sharing, I am working on a MongoDB and .net core project. I have one DB with multiple collections. In start-up class
services.AddSingleton(s => { return new MongoClient(con.ConnectionString).GetDatabase(con.DatabaseName); });
My connection string and DB info are stored inside my appSetting.json. Now in my repo, I inject
mongoDBClient.GetCollection<SomeClass>(GetCollectionNameFromAppSetting((settings.CollectionName)));
Since I am having one Database would that be ok to have that registered as a singleton? or should I change it
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With