2017-05-25 76 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