2017-05-25 80 views
22

我尝试在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' ...

这里是我的ConfigureServicesConfigure方法的服务。

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

回答

40

引用文档

Services Available in Startup

ASP.NET核心依赖注入期间 应用程序的启动提供应用服务。您可以通过将 合适的界面作为参数,将Startup类的 构造函数或其ConfigureConfigureServices方法之一包含在内,以请求这些服务。

在其中 他们被称为顺序在Startup类查看每个方法,以下服务可能会被要求为 参数:

  • 在构造函数中:IHostingEnvironmentILoggerFactory
  • ConfigureServices方法:IServiceCollection
  • Configure方法:IApplicationBuilder,IHostingEnvironment, ILoggerFactoryIApplicationLifetime

您正在试图解决在启动过程中将提供服务,

...CommunicatorContext dbContext, ILdapService ldapService) { 

它会给你你所得到的错误。如果您需要访问的实现,那么你需要做以下之一:

  1. 修改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(); 
    } 
    
  2. 修改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); 
    } 
    
+0

我做了第一次改变,它的工作原理。谢谢 –

+0

谢谢,这解决了我的问题。如果我可以添加更多,在测试这两个选项之后,我发现我仍然需要修改'ConfigureServices'以返回'void'(默认情况下)以返回'IServiceProvider',以便使第二个选项正常工作。 – muhihsan

18

从恩科西解决方案,因为通过调用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创建。

13
.UseDefaultServiceProvider(options => 
      options.ValidateScopes = false) 

Program.cs中后.UseStartup<Startup>()


对我的作品

Documentation Here

4

添加此或者,您可以在Configure方法中创建一个服务范围:

var scopeFactory = ApplicationServices.GetService<IServiceScopeFactory>(); 
using (var scope = scopeFactory.CreateScope()) 
{ 
    var dbContext = scope.ServiceProvider.GetService<CommunicatorDbContext>(); 
    DbInitializer.Initializer(dbContext, ldapService); 
} 

虽然,在时差如前所述,不这样做;-)

+1

这有什么问题?为什么你建议不要这样做。我现在有这个:'''使用(var scope = app.ApplicationServices.CreateScope())scope.ServiceProvider.GetService ()。InitAsync()。Wait();'''我应该这样做一些其他方式? – Ciantic

13

在ASP.NET核2.0 RTM,你可以简单地注入范围的服务,你需要进入Configure构造,就像你试图做最初:

public void Configure(
    IApplicationBuilder app, 
    IHostingEnvironment env, 
    ILoggerFactory loggerFactory, 
    CommunicatorContext dbContext, 
    ILdapService ldapService) 
{ 
    // ... 
} 

这要容易得多,这要归功于#1106的改进。

+0

这是解决问题的自然方法。谢谢。 – harveyt

+0

使用2.0 RTM的最佳方法 – Postlagerkarte