我应该如何注册使用 MongoClient、Singleton 或 scoped 的 mongodb 服务?

Chr*_*ian 10 c# asp.net mongodb

我正在使用 Mongodb 构建一个带有 ASP.NET 核心的 API,我有不同的服务用户服务家庭服务等。我想知道我是否应该将每个服务注册为单例服务,因为它在 asp.net 核心文档中提到,还是作为范围。链接到存储库https://github.com/krisk0su/apartments

用户服务.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);
}
Run Code Online (Sandbox Code Playgroud)

启动文件

services.AddSingleton<UserService>();
            services.AddSingleton<BookService>();
            services.AddSingleton<AuthenticationService>();
            services.AddScoped<IPasswordHasher, PasswordHasher>();
Run Code Online (Sandbox Code Playgroud)

Owa*_*ams 9

2.10 版的MongoDB .NET 驱动程序参考文档在 Mongo 客户端重用部分的参考 > 驱动程序 > 连接页面上解释说:

建议将MongoClient实例存储在全局位置,作为静态变量或具有单例生命周期的 IoC 容器。

关于 Mongo 数据库重用,它没有提到单例生命周期,但它确实说它“是线程安全的并且可以安全地全局存储”,所以我将其解释为意味着它可以安全地存储为单例如果那是您的实现所希望的,但如果您更喜欢另一个生命周期,则不需要。

执行IMongoDatabase由所提供的MongoClient是线程安全和安全地在全球或IoC容器储存。

Mongo Collection Re-use 也是一样的

IMongoCollection<TDocument>由 a 提供的最终实现MongoClient是线程安全的,并且可以安全地存储在全局或 IoC 容器中。

因此,我再次将其解释为意味着生命周期的选择取决于您的特定要求。

看来这仅仅是MongoClient携带建议使用一个单身一辈子。


Vic*_*sov 5

那么它的复杂。

首先MongoClient可以是单例,所以所有使用的服务也MongoClient可以是单例。其重要原因是singleton service不能依赖于更短的life(Scoped、Transient)。

现在关于UserService. 它的所有依赖项都是单例,服务本身不存储任何应该存在有限时间的数据(没有字段,没有道具)或有关特定用户的任何数据等。

所以它可以是单身!

但是,如果您决定添加作用域依赖或在其中存储任何数据:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

那么你必须至少使它成为 Scoped。


顺便说一句,MongoClient在 DI 中作为单例要容易得多:

services.AddSingleton<IMongoClient>(s => 
    new MongoClient(Configuration.GetConnectionString("MongoDb"))
);
Run Code Online (Sandbox Code Playgroud)

然后在所有服务中使用它:

public class UserService
{
    private readonly IMongoCollection<User> users;

    public UserService(IMongoClient mongoClient)
    {
        var database = mongoClient.GetDatabase("DatabaseName");
        users = database.GetCollection<User>(settings.UsersCollectionName);
    }
}

Run Code Online (Sandbox Code Playgroud)

或者,如果您将在您的应用程序中只使用一个数据库,您也可以将 IMongoDatabase 移至 DI,然后您无需每次都在服务构造函数中获取它。