我已经在多个ASP.NET(核心)应用程序中使用了DI,这些应用程序将DbContext注入到控制器构造函数中,并且在对控制器的第一个请求时,构造函数被运行并注入了依赖项。
我现在正在使用一个Web API项目,该项目已连接到Azure消息总线,处理和持久存储总线中的数据,并提供了数据的API终结点。处理和持久化来自Azure Message Bus的消息的类是QueueProcessor
。
我需要从项目开始就保留数据,这意味着我需要一个从项目运行时开始的DbContext实例,而不是从API端点查询数据时的实例。因此,永远不会隐式调用QueueProcessor
的构造函数,如果要手动执行此操作,我需要一个预先存在的MyDbContext
实例传递给它。
我已经研究了几天,尝试了一些手动模式,但是我遇到了并发问题,整个项目目前感觉像是黑客。
这是我目前正在做的事情:
public void ConfigureServices(IServiceCollection services)
{
services.AddHangfire(x => x.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContextPool<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("default")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
然后,我必须创建我的QueueProcessor
的新实例,并在构造函数中使用var context = new MyDbContext()
。这会导致并发问题,并完全否定DI
。
如果像我已经做过数百遍一样,要向DI注入MyDbContext
,则创建类的实例以在QueueProcessor
内运行进程意味着我必须传递{{ 1}}给我自己的构造函数。 VS在设计时将其标记出来。
我曾经尝试过这样做:
MyDbContext
我正在寻找一种更清洁的实现方式:
services.AddTransient(x => new QueueProcessor(x.GetService<MyDbContext>(), Configuration.GetConnectionString("MessageBus")));
中调用一个方法以从项目开始处理Azure Message Bus消息。QueueProcessor
的实例化实例,可用于在处理消息时将其持久化。MyDbContext
来正确设置DI。是否有办法实现这一目标,或者我完全错过了这里的成绩?
答案 0 :(得分:1)
有效的解决方案,不确定是否是最佳模式:
Startup.cs
的机会ConfigureServices
返回IServiceProvider
而不是void
。var serviceProvider = services.BuildServiceProvider();
var context = serviceProvider.GetRequiredService<MyDbContext>();
QueueProcessor
的实例,并将context
传递给构造函数和invoke方法以开始处理消息。ConfigureServices
返回新的serviceProvider
。完整代码块:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("...")));
var serviceProvider = services.BuildServiceProvider();
var localMyDbContext = serviceProvider.GetRequiredService<MyDbContext>();
Processor = new QueueProcessor(localDbContext, Configuration.GetConnectionString("Other"));
Processor.RunAsync().GetAwaiter().GetResult();
return serviceProvider;
}