在Configure方法中,asp net core请求服务返回null

Ant*_*iry 6 c# asp.net configuration asp.net-core

我正在尝试在configure方法中获取一些服务,这样我就可以更轻松地使用它们来构建数据库.

所以我在我的Configure方法中注入了IServiceProvider,但每次都这样做:var service = serviceProvider.GetService<UserService>();它返回null ...

这是我的代码:

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);
        }
    } 
Run Code Online (Sandbox Code Playgroud)

juu*_*nas 8

作为注入的替代方法IServiceProvider,您只需将服务作为参数请求Configure:

public void Configure(
   IApplicationBuilder app,
   IHostingEnvironment env,
   ILoggerFactory loggerFactory,
   ApplicationDbContext context,
   IUserService userService)
{

}
Run Code Online (Sandbox Code Playgroud)

  • 没有理由注入`IServiceProvider`。这是正确的答案。 (2认同)

Set*_*Set 8

当你注册UserService使用

services.AddTransient<IUsersService, UserService>();
Run Code Online (Sandbox Code Playgroud)

代替

var userService = services.GetService<UserService>();
Run Code Online (Sandbox Code Playgroud)

你需要询问接口类型:

var userService = services.GetService<IUserService>();
Run Code Online (Sandbox Code Playgroud)


Tse*_*eng 5

IServiceProvider未在Di / IoC中注册,因为IServiceProvider 是IoC / DI(或使用第三方DI时的包装)。

一旦IServiceProvider被创建,它的依赖配置不能再修改(适用于开箱的IoC)。

当需要依赖时,Configure应将此依赖作为方法参数(方法注入)传递并获取实例。如果您仍然需要访问IServiceProvider,则可以致电app.ApplicationServices。

但是请注意,使用时app.ApplicationServices,您是在应用程序范围的容器中进行解析的。以这种方式解决的每个范围服务或临时服务都将保持活动状态,直到应用程序结束。这是因为在应用程序启动期间没有作用域容器,它是在请求期间创建的。

这意味着,您必须在Configure方法内创建一个作用域,实例化所需的服务,调用它们,然后在离开作用域之前丢弃作用域上下文。

// 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这样可以确保所有服务均被明确处置,并且不存在内存泄漏。如果/当您在DbContext未创建作用域的容器的情况下初始化时,这可能会产生严重影响,例如将DbContext变成单例(因为它将从父容器中解决)或导致内存泄漏,因为在应用程序范围内解析的服务在应用程序的生命周期内仍处于活动状态。