配置方法中的asp net core请求服务返回null

Posted

技术标签:

【中文标题】配置方法中的asp net core请求服务返回null【英文标题】:asp net core requesting service in Configure method returns null 【发布时间】:2017-08-21 06:59:54 【问题描述】:

我正在尝试在 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);
        
     

【问题讨论】:

你需要使用接口:var userService = services.GetService&lt;IUserService&gt;(); 是的,谢谢! 【参考方案1】:

当你注册 UserService 时使用

services.AddTransient<IUsersService, UserService>();

而不是

var userService = services.GetService<UserService>();

您需要询问接口类型:

var userService = services.GetService<IUserService>();

【讨论】:

【参考方案2】:

作为注入IServiceProvider 的替代方法,您可以将服务作为参数请求到Configure

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



【讨论】:

没有理由注入IServiceProvider。这是正确的答案。【参考方案3】:

IServiceProvider 未在 Di/IoC 中注册,因为IServiceProvider 是 IoC/DI(或在使用第 3 方 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();
        
    

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

【讨论】:

为什么使用app.ApplicationServices.GetService&lt;IServiceScopeFactory&gt;().CreateScope() 而不是更简单的app.ApplicationServices.CreateScope() @lonix:没有特别的原因。答案是4岁多了,不知道当时有没有速记法 是的两个are identical。

以上是关于配置方法中的asp net core请求服务返回null的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求

Asp.NET Core:对服务的跨域请求(预检)返回代码 204 而不是 200

Asp.Net Core 入门—— 路由

ASP.NET Core中间件计算Http请求时间

Asp.Net Core 服务生命周期

ASP.NET Core RC2 IIS 在选项请求上返回 502