当我尝试在Configure
文件中的Startup.cs
方法中使用自定义DbContext时,我收到以下异常。我在版本2.0.0-preview1-005977
未处理的异常:System.Exception:无法解析类型为' Communicator.Backend.Data.CommunicatorContext'的服务。对于参数' dbContext'方法'配置'在类型' Communicator.Backend.Startup'。 ---> System.InvalidOperationException:无法解析作用域服务' Communicator.Backend.Data.CommunicatorContext'来自root provider。
当我尝试接收其他实例时,也会抛出此异常。
未处理的异常: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);
}
答案 0 :(得分:62)
引用文档
ASP.NET Core依赖注入期间提供应用程序服务 应用程序的启动。您可以通过包括请求这些服务 适当的界面作为
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);
}
答案 1 :(得分:29)
来自NKosi的解决方案有效,因为通过自己调用services.BuildServiceProvider()
而没有参数,您没有通过validateScopes
。因为禁用此验证,所以不会抛出异常。但这并不意味着问题不存在。
EF Core DbContext
注册了scoped生活方式。在ASP本机DI容器范围连接到IServiceProvider
的实例。通常,当您使用Controller中的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创建服务提供商。
答案 2 :(得分:23)
在ASP.NET Core 2.0及更新版本中,您只需将所需的作用域服务注入Configure
构造函数,就像您最初尝试的那样:
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory,
CommunicatorContext dbContext,
ILdapService ldapService)
{
// ...
}
由于#1106的改进,这很容易。
答案 3 :(得分:17)
.UseDefaultServiceProvider(options =>
options.ValidateScopes = false)
在.UseStartup<Startup>()
适合我
答案 4 :(得分:5)
或者,您可以在Configure
方法中创建服务范围:
var scopeFactory = ApplicationServices.GetService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
var dbContext = scope.ServiceProvider.GetService<CommunicatorDbContext>();
DbInitializer.Initializer(dbContext, ldapService);
}
虽然如Slack所述,但不要这样做; - )