1 回答

TA貢獻1942條經驗 獲得超3個贊
為了了解發(fā)生了什么,您首先必須了解依賴注入生命周期之間的差異:
瞬態(tài):為每個解決的依賴關系創(chuàng)建一個新實例。
Singleton:每當服務得到解決時,就會使用單個共享實例。
范圍:每當服務在單個范圍(或請求)內得到解析時,就會共享單個實例。后續(xù)請求將意味著將再次創(chuàng)建一個新實例。
數據庫上下文保存與數據庫的連接。這就是為什么您通常不希望它成為單例,這樣您就不會在應用程序的整個生命周期中保持單個連接打開。所以你想讓它成為暫時的。但是,如果您需要在處理單個請求時多次訪問數據庫,則需要在短時間內多次打開數據庫連接。因此,折衷方案是默認使其成為范圍依賴項:這樣您就不會長時間保持連接打開,但您仍然可以在短時間內重用連接。
現在,讓我們考慮一下當單例服務依賴于非單例服務時會發(fā)生什么:單例服務只創(chuàng)建一次,因此它的依賴關系也只解決一次。這意味著它所具有的任何依賴項現在都在該服務的整個生命周期(即應用程序的生命周期)中有效共享。因此,通過依賴非單例服務,您可以有效地使這些服務成為準單例。
這就是為什么(在開發(fā)期間)存在保護措施,可以防止您犯此錯誤:作用域驗證將檢查您是否不依賴于作用域之外的作用域服務,例如在單例服務內。這樣,您就不會逃避該范圍服務的預期生命周期。
當您現在AppIdentityDbContext.CreateAdminAccount
在該方法內運行時Configure
,您是在范圍之外運行它。所以你基本上處于“單身土地”內。您現在創(chuàng)建的任何依賴項都將保留。由于您解析了UserManager<AppUser>
和RoleManager<IdentityRole>
兩者都依賴于作用域數據庫上下文,因此您現在正在轉義數據庫上下文的配置作用域生命周期。
為了解決這個問題,您應該創(chuàng)建一個短暫的作用域,然后您可以在其中訪問作用域服務(因為您位于作用域內),當作用域終止時,這些服務將被正確清理:
public static async Task CreateAdminAccount(IServiceProvider serviceProvider, IConfiguration configuration)
{
// get service scope factory (you could also pass this instead of the service provider)
var serviceScopeFactory = serviceProvider.GetService<IServiceScopeFactory>();
// create a scope
using (var scope = serviceScopeFactory.CreateScope())
{
// resolve the services *within that scope*
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<AppUser>>();
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
// do stuff
}
// scope is terminated after the using ends, and all scoped dependencies will be cleaned up
}
- 1 回答
- 0 關注
- 121 瀏覽
添加回答
舉報