ASP.NET Core 2中的依赖注入会引发异常

时间:2017-05-25 12:37:18

标签: c# asp.net-core asp.net-core-2.0

当我尝试在Configure文件中的Startup.cs方法中使用自定义DbContext时,我收到以下异常。我在版本2.0.0-preview1-005977

中使用ASP.NET Core
  

未处理的异常:System.Exception:无法解析类型为' Communicator.Backend.Data.CommunicatorContext'的服务。对于参数' dbContext'方法'配置'在类型' Communicator.Backend.Startup'。 ---> System.InvalidOperationException:无法解析作用域服务' Communicator.Backend.Data.CommunicatorContext'来自root provider。

当我尝试接收其他实例时,也会抛出此异常。

  

未处理的异常: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);
}

5 个答案:

答案 0 :(得分:62)

引用文档

  

Services Available in Startup

     

ASP.NET Core依赖注入期间提供应用程序服务   应用程序的启动。您可以通过包括请求这些服务   适当的界面作为Startup课程的参数   构造函数或其ConfigureConfigureServices方法之一。

     

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

     
      
  • 在构造函数中:IHostingEnvironmentILoggerFactory
  •   
  • 使用ConfigureServices方法:IServiceCollection
  •   
  • Configure方法中:IApplicationBuilderIHostingEnvironment,   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);
    }
    

答案 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>()

之后在Program.cs中添加它


适合我

Documentation Here

答案 4 :(得分:5)

或者,您可以在Configure方法中创建服务范围:

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

虽然如Slack所述,但不要这样做; - )