问题描述
我有与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容器中。
然后我的问题是:是否有更好的方法将MongoDB与带有.NET Core的多个集合一起使用(某种连接this question),还是使用“通用惰性”方法更好?
解决方法
我认为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,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;
}
}
,
您可以在“服务”容器中注册IMongoDatabase的单个实例。那么您可以使用IMongoDatabase实例将Singleton Collections添加到您的服务容器中。
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;
}
}