usemvcwithdefaultroute services net mvc iservicecollection inyeccion injection dependency dependencias configureservices asp c# asp.net-core asp.net-core-2.0

c# - services - La inyección de dependencia en ASP.NET Core 2 lanza una excepción



iservicecollection (5)

Alternativamente, puede crear un alcance de servicio dentro de su método de Configure :

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

Aunque, como se menciona en Slack, no hagas esto ;-)

Recibo la siguiente excepción cuando trato de usar DbContext personalizado en el método Configure en el archivo Startup.cs . Uso ASP.NET Core en la versión 2.0.0-preview1-005977

Excepción no controlada: System.Exception: No se pudo resolver un servicio de tipo ''Communicator.Backend.Data.CommunicatorContext'' para el parámetro ''dbContext'' del método ''Configurar'' en el tipo ''Communicator.Backend.Startup''. ---> System.InvalidOperationException: No se puede resolver el servicio con ámbito ''Communicator.Backend.Data.CommunicatorContext'' del proveedor raíz.

Esta excepción también se produce en caso de que intente recibir otra instancia.

Excepción no controlada: System.Exception: no se pudo resolver un servicio del tipo ''Communicator.Backend.Services.ILdapService'' ...

Aquí están mis métodos ConfigureServices y 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); }


Citando documentación

Servicios disponibles en Startup

La inyección de dependencia de ASP.NET Core proporciona servicios de aplicación durante el inicio de una aplicación. Puede solicitar estos servicios al incluir la interfaz apropiada como un parámetro en el constructor de su clase de Startup o uno de sus métodos Configure o ConfigureServices .

Al examinar cada método en la clase de Startup en el orden en que se llaman, se pueden solicitar los siguientes servicios como parámetros:

  • En el constructor: IHostingEnvironment , ILoggerFactory
  • En el método ConfigureServices : IServiceCollection
  • En el método de Configure : IApplicationBuilder , IHostingEnvironment , ILoggerFactory , IApplicationLifetime

Está intentando resolver servicios que no están disponibles durante el inicio,

...CommunicatorContext dbContext, ILdapService ldapService) {

Lo que le dará los errores que está recibiendo. Si necesita acceder a las implementaciones, debe realizar una de las siguientes acciones:

  1. Modifique el método ConfigureServices y acceda a ellos desde la colección de servicios. es decir

    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. Modifique el método ConfigureServices para devolver IServiceProvider, Configure método para tomar un IServiceProvider y luego resuelva sus dependencias allí. es decir

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


En ASP.NET Core 2.0 y versiones más recientes, simplemente puede inyectar el servicio con ámbito que necesita en el constructor de Configure , como intentó hacerlo inicialmente:

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

Esto es mucho más fácil, gracias a las mejoras en https://github.com/aspnet/Hosting/pull/1106 .


La solución de NKosi funciona porque al invocar services.BuildServiceProvider() usted mismo sin parámetros, no está pasando los validateScopes . Debido a que esta validación está deshabilitada, la excepción no se lanza. Esto no significa, sin embargo, el problema no está allí.

EF Core DbContext está registrado con un estilo de vida de ámbito. En ASP, el contenedor DI nativo está conectado a la instancia de IServiceProvider . Normalmente, cuando usa su DbContext desde el Controlador, no hay problema porque ASP crea un nuevo ámbito (nueva instancia de IServiceProvider ) para cada solicitud y luego lo usa para resolver todo lo que hay dentro de esta solicitud. Sin embargo, durante el inicio de la aplicación no tiene un alcance de solicitud. Tiene una instancia de IServiceProvider que no está dentro del alcance (o en otras palabras, en el ámbito raíz). Esto significa que usted debe crear alcance usted mismo. Puedes hacerlo así:

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 }

El método ConfigureServices puede permanecer sin cambios.

EDITAR

Su solución funcionará en 2.0.0 RTM sin ningún cambio, ya que en RTM, se creará un proveedor de servicios para el método de configuración https://github.com/aspnet/Hosting/pull/1106 .


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

agregue esto en Program.cs después de .UseStartup<Startup>()


Funciona para mi

Documentacion aqui