NET核心Web API和具有多个集合的MongoDB

l7wslrjt  于 2022-12-03  发布在  Go
关注(0)|答案(5)|浏览(145)

我有与MongoDB交互的WebAPI。
我使用惰性方法将我的所有MongoDB集合类创建为单例。我知道这是一种“标准”方法,但由于我的Web API使用的是.NET Core,因此我发现这个tutorial乍看起来描述了如何为.NET Core应用程序更高效地完成它。
无论如何,它解释了如何用一个数据库来做,只包含一个集合,这是相当有限的。
例如,对于2个集合,它似乎甚至被弃用。例如,这部分代码:

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

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

如果我有第二个具有相同类型构造函数的集合,它将创建一个MongoClient的新示例,MongoDB文档不建议这样做:
建议将MongoClient示例存储在一个全局位置,或者作为一个静态变量,或者存储在一个具有单例生存期的IoC容器中。
我的问题是:有没有更好的方法将MongoDB与多个集合一起与.NET Core一起使用(类似于join this question),或者使用“通用惰性”方法更好?

c8ib6hqw

c8ib6hqw1#

我认为,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;
    }
}
2w3rbyxf

2w3rbyxf2#

您可以在服务容器中注册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;
   }
}
vxbzzdmp

vxbzzdmp3#

我正在处理一个将有多个集合的项目。我不确定如何构造appSetting.json文件:

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

},是不是可以做一个集合名的数组:

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

axr492tv4#

我将它注册为一个单例,如下所示:

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

我从appsettings.json获得如下设置:

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

我在我的存储库中这样使用:

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

gblwokeq5#

我只是返回一个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>();

然后我这样使用:

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

现在,您有了一个MongoClient,可以为任意n个集合自由连接到任何数据库

相关问题