2017-03-28 13 views
3

我試圖在配置方法中獲得一些服務,這樣我就可以使我的數據庫更容易。配置方法中的asp net內核請求服務返回null

所以我注入的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); 
     } 
    } 
+1

你需要使用接口:'VAR userService =服務.GetService ();' – Set

+0

是的,它做到了,謝謝! –

回答

3

如您使用註冊UserService

services.AddTransient<IUsersService, UserService>(); 

,而不是

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

你需要問的接口類型:

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

作爲替代注射IServiceProvider ,您可以請求服務作爲參數Configure

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

} 
+1

沒有理由注入'IServiceProvider'。這是正確的答案。 – ssmith

1

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

這確保了所有的服務都清楚地處理了,並且您沒有內存泄漏。如果/在初始化DbContext而未創建作用域容器(如將DbContext轉換爲單例(因爲它將從父容器解析)或導致內存泄漏,因爲在應用程序作用域中解析的服務在應用。