ASP.NET Core 2中的依赖注入抛出异常
我尝试在Startup.cs
文件中使用Configure
方法中的自定义DbContext时收到以下异常。我使用ASP.NET核心版本2.0.0-preview1-005977ASP.NET Core 2中的依赖注入抛出异常
未处理的异常:System.Exception的:无法解析类型的服务“Communicator.Backend.Data.CommunicatorContext”为参数“的DbContext”类型为'Communicator.Backend.Startup'的方法'Configure'。 ---> System.InvalidOperationException:无法解析根提供程序的范围服务'Communicator.Backend.Data.CommunicatorContext'。
当我尝试接收其他实例时,也会抛出此异常。
未处理的异常:System.Exception的:无法解析型 'Communicator.Backend.Services.ILdapService'
...
这里是我的ConfigureServices
和Configure
方法的服务。
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CommunicatorContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddCookieAuthentication();
services.Configure<LdapConfig>(Configuration.GetSection("Ldap"));
services.AddScoped<ILdapService, LdapService>();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, CommunicatorContext dbContext, ILdapService ldapService)
{
app.UseAuthentication();
app.UseWebSockets();
app.Use(async (context, next) =>
{
if (context.Request.Path == "/ws")
{
if (context.WebSockets.IsWebSocketRequest)
{
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Echo(context, webSocket);
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await next();
}
});
app.UseMvc();
DbInitializer.Initialize(dbContext, ldapService);
}
引用文档
ASP.NET核心依赖注入期间 应用程序的启动提供应用服务。您可以通过将 合适的界面作为参数,将
Startup
类的 构造函数或其Configure
或ConfigureServices
方法之一包含在内,以请求这些服务。在其中 他们被称为顺序在
Startup
类查看每个方法,以下服务可能会被要求为 参数:
- 在构造函数中:
IHostingEnvironment
,ILoggerFactory
- 在
ConfigureServices
方法:IServiceCollection
- 在
Configure
方法:IApplicationBuilder
,IHostingEnvironment
,ILoggerFactory
,IApplicationLifetime
您正在试图解决在启动过程中将提供服务,
...CommunicatorContext dbContext, ILdapService ldapService) {
它会给你你所得到的错误。如果您需要访问的实现,那么你需要做以下之一:
-
修改
ConfigureServices
方法,并从服务收集有访问它们。即public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddDbContext<CommunicatorContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddCookieAuthentication(); services.Configure<LdapConfig>(Configuration.GetSection("Ldap")); services.AddScoped<ILdapService, LdapService>(); services.AddMvc(); // Build the intermediate service provider var serviceProvider = services.BuildServiceProvider(); //resolve implementations var dbContext = serviceProvider.GetService<CommunicatorContext>(); var ldapService = serviceProvider.GetService<ILdapService>(); DbInitializer.Initialize(dbContext, ldapService); //return the provider return serviceProvider(); }
-
修改
ConfigureServices
方法返回的IServiceProvider,Configure
方法采取IServiceProvider
,然后解决您的依赖那里。即public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddDbContext<CommunicatorContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); services.AddCookieAuthentication(); services.Configure<LdapConfig>(Configuration.GetSection("Ldap")); services.AddScoped<ILdapService, LdapService>(); services.AddMvc(); // Build the intermediate service provider then return it return services.BuildServiceProvider(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider) { //...Other code removed for brevity app.UseMvc(); //resolve dependencies var dbContext = serviceProvider.GetService<CommunicatorContext>(); var ldapService = serviceProvider.GetService<ILdapService>(); DbInitializer.Initialize(dbContext, ldapService); }
从恩科西解决方案,因为通过调用services.BuildServiceProvider()
自己不带参数的你是不是经过validateScopes
工作。因为此验证被禁用,所以不会引发异常。但这并不意味着问题不存在。
EF核心DbContext
注册范围生活方式。在ASP本地DI容器作用域连接到IServiceProvider
的实例。通常情况下,当您使用控制器中的DbContext
时,不会出现问题,因为ASP会为每个请求创建新范围(IServiceProvider
的新实例),然后使用它来解决此请求中的所有问题。但是,在应用程序启动期间,您没有请求范围。您有IServiceProvider
的实例没有作用域(或换言之,在根作用域中)。这意味着你应该自己创建示波器。你可以这样做:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
var scopeFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<CommunicatorContext>();
var ldapService = scope.ServiceProvider.GetRequiredService<ILdapService>();
// rest of your code
}
// rest of Configure setup
}
ConfigureServices
方法可以保持不变。
编辑
您的解决方案将在2.0.0 RTM工作,没有任何变化,因为在RTM范围的服务供应商将用于配置方法https://github.com/aspnet/Hosting/pull/1106创建。
.UseDefaultServiceProvider(options =>
options.ValidateScopes = false)
Program.cs中后.UseStartup<Startup>()
对我的作品
添加此或者,您可以在Configure
方法中创建一个服务范围:
var scopeFactory = ApplicationServices.GetService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetService<CommunicatorDbContext>();
DbInitializer.Initializer(dbContext, ldapService);
}
虽然,在时差如前所述,不这样做;-)
这有什么问题?为什么你建议不要这样做。我现在有这个:'''使用(var scope = app.ApplicationServices.CreateScope())scope.ServiceProvider.GetService
在ASP.NET核2.0 RTM,你可以简单地注入范围的服务,你需要进入Configure
构造,就像你试图做最初:
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
CommunicatorContext dbContext,
ILdapService ldapService)
{
// ...
}
这要容易得多,这要归功于#1106的改进。
这是解决问题的自然方法。谢谢。 – harveyt
使用2.0 RTM的最佳方法 – Postlagerkarte
我做了第一次改变,它的工作原理。谢谢 –
谢谢,这解决了我的问题。如果我可以添加更多,在测试这两个选项之后,我发现我仍然需要修改'ConfigureServices'以返回'void'(默认情况下)以返回'IServiceProvider',以便使第二个选项正常工作。 – muhihsan