mongodb服务-单例还是有范围的?

时间:2020-01-05 10:56:25

标签: c# asp.net mongodb

我正在使用Mongodb构建带有ASP.NET核心的API,并且我拥有不同的服务,用户服务家庭服务等。我想知道我应该将每个服务注册为asp.net核心文档中提到的单例还是作为范围。链接到存储库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>();

2 个答案:

答案 0 :(得分:4)

很复杂。

首先MongoClient可以是singleton,因此所有使用MongoClient的服务也可以是单例。它的重要原因是单例服务不能依赖寿命较短的服务(作用域,瞬态)。

现在介绍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();
    }
}

然后您必须使其至少具有作用范围。


在DI中将MongoClient作为单身人士要容易得多:

services.AddSingleton<IMongoClient>(s => 
    new MongoClient(Configuration.GetConnectionString("MongoDb"))
);

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

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

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

或者,如果您仅在应用程序中使用一个数据库,则也可以将IMongoDatabase移至DI,这样就不必每次都在服务构造函数中获取它。

答案 1 :(得分:4)

版本2.10的MongoDB .NET Driver参考文档在Mongo Client Reference > Driver > Connecting部分的Re-use页上进行了解释,

建议将MongoClient实例存储为全局变量,既可以作为静态变量,也可以存储在具有单例寿命的IoC容器中。

关于Mongo数据库Re-use,它没有提到单例生命期,但确实说“ 是线程安全的,可以安全地存储在全球范围内”,所以我会解释这意味着,如果您的实现需要这样做,则可以将它安全地存储为一个单例,但是如果您希望拥有另一个生存期,则不必如此。

IMongoDatabase提供的MongoClient的实现是线程安全的,可以安全地全局存储或存储在IoC容器中。

关于Mongo Collection Re-use的问题是相同的:

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

所以我再次解释说,寿命的选择取决于您的特定要求。

似乎只有MongoClient带有建议才能使用单例寿命。