Estoy tratando de obtener algunos de mis servicios en el método de configuración para poder sembrar mi base de datos más fácilmente con ellos.
Así que inyecté IServiceProvider en mi método Configurar, pero cada vez que lo hago: var service = serviceProvider.GetService<UserService>(); devuelve nulo...
Aquí está mi código:
public class Startup { public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true); builder.AddEnvironmentVariables(); Configuration = builder.Build(); } public IConfigurationRoot Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(this.Configuration.GetConnectionString("DbConnectionString"))); // Add framework services. services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<IdentityDbContext>().AddDefaultTokenProviders(); string connection = this.Configuration.GetConnectionString("DbConnectionString"); services.AddEntityFramework(); services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connection)); services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.Configure<AppSettings>(this.Configuration.GetSection("AppSettings")); services.AddScoped<IsAuthorized>(); services.AddSingleton<UserManager<ApplicationUser>>(); services.AddTransient<IUsersService, UserService>(); services.AddMvc(config => { config.Filters.Add(typeof(SingletonUsers)); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider services) { loggerFactory.AddConsole(this.Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseMvc(); // This returns the context. var context = services.GetService<ApplicationDbContext>(); // This returns null. var userService = services.GetService<UserService>(); // Can't work without the UserService MyDbInitializer.Initialize(context, userService); } }como registró UserService usando
services.AddTransient<IUsersService, UserService>();en vez de
var userService = services.GetService<UserService>();debe solicitar el tipo de interfaz:
var userService = services.GetService<IUserService>();Como alternativa a inyectar IServiceProvider , puede solicitar los servicios como parámetros para Configure :
public void Configure( IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, ApplicationDbContext context, IUserService userService) { }IServiceProvider no está registrado con Di/IoC, porque IServiceProvider es IoC/DI (o un contenedor a su alrededor, cuando se usa DI de terceros).
Una vez que se crea un IServiceProvider , su configuración de dependencia ya no se puede cambiar (esto se aplica al IoC listo para usar).
Cuando necesite una dependencia en Configure , debe pasar esta dependencia como parámetro del método (inyección de método) y obtener la instancia. Si aún necesita acceder a IServiceProvider , puede hacerlo llamando a app.ApplicationServices .
Pero tenga en cuenta que cuando usa app.ApplicationServices , está resolviendo desde el contenedor de toda la aplicación. Todo servicio con alcance o transitorio resuelto de esta manera, permanecerá activo hasta que finalice la aplicación. Esto se debe a que durante el inicio de la aplicación no hay un contenedor con ámbito, se crea durante una solicitud.
Esto significa que debe crear un ámbito dentro del método Configure , instanciar los servicios que necesita, llamarlos y luego desechar el contexto del ámbito antes de dejarlo.
// Example of EF DbContext seeding I use in my application using (var scope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope()) { using (var context = scope.ServiceProvider.GetRequiredService<MyDbContext>()) { if(context.Database.EnsureCreated()) { context.SeedAsync().Wait(); } } } Esto asegura que todos los servicios estén claramente dispuestos y que no tenga pérdidas de memoria. Esto puede tener un impacto severo si/cuando inicializa DbContext sin crear un contenedor con ámbito, como convertir DbContext en un único (porque se resolverá desde el contenedor principal) o causar pérdidas de memoria porque los servicios resueltos en el ámbito de la aplicación permanecen activos durante la vida útil del solicitud.