简体   繁体   English

ASP.NET Core Web API and MongoDB with multiple Collections

[英]ASP.NET Core Web API and MongoDB with multiple Collections

I have WebAPI which interacts with MongoDB.我有与 MongoDB 交互的 WebAPI。

I created all of my MongoDB collection classes as singleton using the lazy approach .我使用惰性方法将所有 MongoDB 集合类创建为 singleton。 I understood it was a "standard" approach, but since I am using .NET Core for my web API, I found this tutorial that at first glance described how to do it more efficiently for .NET Core apps.我知道这是一种“标准”方法,但由于我正在为我的 .NET 核心使用 web API,我发现本教程乍一看描述了如何更有效地为 .NET 核心应用程序执行此操作。

Anyway, it explains how to do it with one database, containing one collection only, which is quite limited.不管怎样,它解释了如何用一个数据库来做,只包含一个集合,这是非常有限的。

With for example 2 collections, it seems even deprecated.例如 2 collections,它似乎甚至被弃用了。 For example 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);
}

If I have a second collection with the same kind of constructor, it will create a new instance of MongoClient which is not recommended by the MongoDB documentation :如果我有第二个具有相同类型构造函数的集合,它将创建一个新的 MongoClient 实例, MongoClient 文档不推荐这样做:

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.建议将 MongoClient 实例存储在全局位置,作为 static 变量或在具有 singleton 生命周期的 IoC 容器中。

My question then is: is there a better way of using MongoDB with multiple collections with .NET Core (kind of join this question ), or is it better to use the "universal lazy" way?那么我的问题是:是否有更好的方法将 MongoDB 与多个 collections 和 .NET 核心一起使用(有点加入这个问题),还是使用“通用惰性”方式更好?

I think, Retic's approach is not so bad.我认为,Retic 的做法还不错。

Lets continue on his answer and extract the database configuration into a separate method ConfigureMongoDb:让我们继续他的回答并将数据库配置提取到一个单独的方法 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);
}

or in a more compact form:或更紧凑的形式:

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));
    }
}

The downside with this approach is, that all mongodb related instances (except the services) are created at startup.这种方法的缺点是,所有与 mongodb 相关的实例(服务除外)都是在启动时创建的。 This is not always bad, because in the case of wrong settings or other mistakes you get immediate response on startup.这并不总是坏事,因为在设置错误或其他错误的情况下,您会在启动时立即得到响应。

If you want lazy initialization for this instances, you can register the database creation and the collection retrieval with a factory method:如果您想对此实例进行延迟初始化,可以使用工厂方法注册数据库创建和集合检索:

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));
    }
}

In the service you have to inject just the registered collection.在服务中,您必须只注入已注册的集合。

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;
    }
}

You can register a single Instance of the IMongoDatabase in your Services container.您可以在服务容器中注册 IMongoDatabase 的单个实例。 then you can add Singleton Collections to your services container using the IMongoDatabase Instance.然后您可以使用 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>();

to use these you would expose your services to your controllers via the controllers constructor.要使用这些,您将通过控制器构造函数将您的服务公开给您的控制器。

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

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

I am working on a project that will have multiple collection.我正在研究一个将有多个集合的项目。 I am not sure about how to structure the appSetting.json file:我不确定如何构建 appSetting.json 文件:

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

}, is it fine to have to do an array of the collection name: },是否可以做一个集合名称的数组:

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

I register it as a singleton like this:我将它注册为这样的单例:

builder.Services.Configure<DatabaseSettings>(builder.Configuration.GetSection("DatabaseSettings"));

builder.Services.AddSingleton<IMongoDatabase>(sp => {
    
    var databaseSettings = sp.GetRequiredService<IOptions<DatabaseSettings>>().Value;
    var mongoDbClient = new MongoClient(databaseSettings.ConnectionString);
    var mongoDb = mongoDbClient.GetDatabase(databaseSettings.DatabaseName);

    return mongoDb;
});


builder.Services.AddScoped<IStudentRepository, StudentRepository>();

I get settings from appsettings.json like this:我从 appsettings.json 获取设置,如下所示:

{
  "DatabaseSettings": {
    "ConnectionString": "mongodb+srv://xwezi:MyPassword@school-cluster.65eoe.mongodb.net",
    "DatabaseName": "school"
  }
}

and I'm using in my repository like this:我在我的存储库中使用这样的:

public class StudentRepository : IStudentRepository
{
    private readonly DatabaseSettings databaseSettings;
    private readonly IMongoCollection<Student> students;

    public StudentRepository(
        IOptions<DatabaseSettings> databaseOptions,
        IMongoDatabase mongoDatabase)
    {
        databaseSettings = databaseOptions.Value;
        students = mongoDatabase.GetCollection<Student>("students");
    }

    public Student? GetStudent(string id)
    {
        return students?.Find(s => s.Id == id).FirstOrDefault();
    }

    public IList<Student>? GetStudents()
    {
        return students?.Find(s => true).ToList();
    }
}

I return just a mongo client when i register it and get the database later.. i don't see any reason why not to?当我注册并稍后获取数据库时,我只返回一个 mongo 客户端。我看不出有什么理由不这样做?

builder.Services.AddSingleton<IMongoClient>(options => {
    var settings = builder.Configuration.GetSection("MongoDBSettings").Get<MongoDBSettings>();
    var client = new MongoClient(settings.ConnectionString);
    return client;
});
builder.Services.AddSingleton<IvMyRepository, vMyRepository>();

Then i use like this:然后我这样使用:

    public vapmRepository(IMongoClient mongoClient)
    {
        IMongoDatabase mongoDatabase = mongoClient.GetDatabase("mdb01");
        _vprocesshealthCollection = mongoDatabase.GetCollection<vMsg>("vhealth");
    }

Now you have a MongoClient and can connect to any database(s) you want freely for any n collections现在你有一个MongoClient并且可以连接到任何你想要的任何数据库 n collections

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM