【问题标题】:ASP.NET Core Web API and MongoDB with multiple Collections具有多个集合的 ASP.NET Core Web API 和 MongoDB
【发布时间】:2020-08-29 14:42:32
【问题描述】:

我有与 MongoDB 交互的 WebAPI。

我使用 lazy approach 将我的所有 MongoDB 集合类创建为单例。我知道这是一种“标准”方法,但由于我将 .NET Core 用于我的 Web API,我发现tutorial 乍一看描述了如何更有效地为 .NET Core 应用程序执行此操作。

不管怎样,它解释了如何使用一个数据库,只包含一个集合,这是非常有限的。

例如 2 个集合,它似乎已被弃用。例如this part of code:

public BookService(IBookstoreDatabaseSettings settings)
{
    var client = new MongoClient(settings.ConnectionString);
    var database = client.GetDatabase(settings.DatabaseName);

    _books = database.GetCollection<Book>(settings.BooksCollectionName);
}

如果我有第二个具有相同构造函数的集合,它将创建MongoClient 的新实例,MongoDB documentation 不建议这样做:

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

然后我的问题是:有没有更好的方法使用 .NET Core 的多个集合使用 MongoDB(有点加入 this question),还是使用“通用惰性”方式更好?

【问题讨论】:

标签: c# mongodb asp.net-core dependency-injection singleton


【解决方案1】:

我认为,Retic 的做法还不错。

让我们继续他的回答并将数据库配置提取到单独的方法 ConfigureMongoDb 中:

public void ConfigureServices(IServiceCollection services)
{
    ConfigureMongoDb(services);

    services.AddControllers()
        .AddNewtonsoftJson(options => options.UseMemberCasing());
}

private void ConfigureMongoDb(IServiceCollection services)
{
    var settings = GetMongoDbSettings();
    var db = CreateMongoDatabase(settings);

    var collectionA = db.GetCollection<Author>(settings.AuthorsCollectionName);
    services.AddSingleton(collectionA);
    services.AddSingleton<AuthorService>();

    var collectionB = db.GetCollection<Book>(settings.BooksCollectionName);
    services.AddSingleton(collectionB);
    services.AddSingleton<BookService>();
}

private BookstoreDatabaseSettings GetMongoDbSettings() =>
    Configuration.GetSection(nameof(BookstoreDatabaseSettings)).Get<BookstoreDatabaseSettings>();

private IMongoDatabase CreateMongoDatabase(BookstoreDatabaseSettings settings)
{
    var client = new MongoClient(settings.ConnectionString);
    return client.GetDatabase(settings.DatabaseName);
}

或更紧凑的形式:

private void ConfigureMongoDb(IServiceCollection services)
{
    var settings = GetMongoDbSettings();
    var db = CreateMongoDatabase(settings);

    AddMongoDbService<AuthorService, Author>(settings.AuthorsCollectionName);
    AddMongoDbService<BookService, Book>(settings.BooksCollectionName);

    void AddMongoDbService<TService, TModel>(string collectionName)
    {
        services.AddSingleton(db.GetCollection<TModel>(collectionName));
        services.AddSingleton(typeof(TService));
    }
}

这种方法的缺点是,所有与 mongodb 相关的实例(服务除外)都是在启动时创建的。 这并不总是很糟糕,因为在设置错误或其他错误的情况下,您会在启动时立即得到响应。

如果您想对此实例进行延迟初始化,可以使用工厂方法注册数据库创建和集合检索:

public void ConfigureMongoDb(IServiceCollection services)
{
    var settings = GetMongoDbSettings();
    services.AddSingleton(_ => CreateMongoDatabase(settings));

    AddMongoDbService<AuthorService, Author>(settings.AuthorsCollectionName);
    AddMongoDbService<BookService, Book>(settings.BooksCollectionName);

    void AddMongoDbService<TService, TModel>(string collectionName)
    {
        services.AddSingleton(sp => sp.GetRequiredService<IMongoDatabase>().GetCollection<TModel>(collectionName));
        services.AddSingleton(typeof(TService));
    }
}

在服务中,您只需注入已注册的集合。

public class BookService
{
    private readonly IMongoCollection<Book> _books;

    public BookService(IMongoCollection<Book> books)
    {
        _books = books;
    }
}

public class AuthorService
{
    private readonly IMongoCollection<Author> _authors;

    public AuthorService(IMongoCollection<Author> authors)
    {
        _authors = authors;
    }
}

【讨论】:

  • 好的,谢谢,我认为这让我朝着正确的方向前进。仍然为什么我不能做 services.AddSingleton(new AuthorService(collectionA)); 而不是 services.AddSingleton(collectionA); + services.AddSingleton&lt;AuthorService&gt;(); ?这两者有什么区别?
  • @loyd.f:当然你可以像这样注册 AuthorService:services.AddSingleton(new AuthorService(db.GetCollection&lt;Author&gt;(settings.AuthorsCollectionName)));。不同之处在于在这种情况下 AuthorService 实例将在启动时创建,否则它将在第一次创建控制器时创建,然后才创建。只有在客户端调用 Uri (https://..../api/authors) 时才会创建 AuthorsController。如果这从未发生过,如果您使用 services.AddSingleton&lt;AuthorService&gt;(),则不会创建 AuthorsController 和 AuthorService
  • @Peter,你能在这里看到我的扩展问题并给我一些建议吗?感谢和赞赏! stackoverflow.com/questions/71232942/…
【解决方案2】:

您可以在服务容器中注册 IMongoDatabase 的单个实例。然后您可以使用 IMongoDatabase 实例将单例集合添加到您的服务容器中。

var client = new MongoClient(connectionString);
var db = client.GetDatabase(dbName);
 
var collectionA = db.GetCollection<Model>(collectionName);
services.AddSingleton<IMongoDatabase, db>();
services.AddSingleton<IMongoCollection, collectionA>();

要使用这些,您需要通过控制器构造函数将服务公开给控制器。

public class SomeController
{
   private readonly IMongoCollection<SomeModel> _someCollection;

   public SomeController(IMongoCollection<SomeModel> someCollection)
   {
      _someCollection = someCollection;
   }
}

【讨论】:

    【解决方案3】:

    我正在做一个有多个收藏的项目。我不确定如何构建 appSetting.json 文件:

    "DatabaseSettings": {
    "ConnectionString": "somestrings",
    "DatabaseName": "somename",
    "CollectionName": "One Collection"
    

    }, 必须做一个集合名称的数组是否可以:

    "DatabaseSettings": {
        "ConnectionString": "somestrings",
        "DatabaseName": "somename",
        "CollectionName": ["One Collection", "Second Collection" "Third Collection"]
      }, 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-08
      • 1970-01-01
      相关资源
      最近更新 更多