国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - ASP.NET Core 3框架揭秘之 異步線程無法使用IServiceProvider問題

ASP.NET Core 3框架揭秘之 異步線程無法使用IServiceProvider問題

2020-06-23 14:05Artech ASP.NET教程

這篇文章主要介紹了ASP.NET Core 3框架揭秘之異步線程無法使用IServiceProvider問題,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下

標題反映的是上周五一個同事咨詢我的問題,我覺得這是一個很好的問題。這個問題有助于我們深入理解依賴注入框架在ASP.NET Core中的應用,以及服務實例的生命周期。

 

一、問題重現

 

我們通過一個簡單的實例來模擬該同事遇到的問題。我們采用極簡的方式創建了如下這個ASP.NET Core MVC應用。如下面的代碼片段所示,除了注冊與ASP.NET Core MVC框架相關的服務與中間件之外,我們還調用了IHostBuilder的UseDefaultServiceProvider方法將配置選項ServiceProviderOptions的ValidateScopes屬性設置為True,以開啟針對服務范圍的驗證。我們還采用Scoped生命周期模式注冊了服務IFoobar,具體的實現類型Foobar還實現了IDisposable接口。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Program
{
 public static void Main()
 {
 Host
 .CreateDefaultBuilder()
 .UseDefaultServiceProvider(options => options.ValidateScopes = true)
 .ConfigureWebHostDefaults(builder => builder
 .ConfigureLogging(logging => logging.ClearProviders())
 .ConfigureServices(services => services
  .AddScoped<IFoobar, Foobar>()
  .AddRouting()
  .AddControllers())
 .Configure(app => app
  .UseRouting()
  .UseEndpoints(endpoints => endpoints.MapControllers())))
 .Build()
 .Run();
 }
}
 
public interface IFoobar { }
public class Foobar : IFoobar, IDisposable
{
 public void Dispose() => Console.WriteLine("Foobar.Dispose();");
}

我們創建了如下這個HomeController,它的構造函數中注入了一個IServiceProvider對象。在Action方法Index中,我們調用Task的靜態方法Run異步執行了一些操作。具體來說,在異步執行的操作中,我們利用調用上面注入的這個IServiceProvider對象的GetRequiredService<T>方法試圖獲取一個IFoobar服務實例。由于這段操作時在一個Try/Catch中執行的,拋出的異常消息的堆棧信息會直接輸出到控制臺上。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class HomeController: Controller
{
 private readonly IServiceProvider _requestServices;
 public HomeController(IServiceProvider requestServices)
 {
 _requestServices = requestServices;
 }
 [HttpGet("/")]
 public IActionResult Index()
 {
 Task.Run(async() => {
 try
 {
 await Task.Delay(100);
 var foobar = _requestServices.GetRequiredService<IFoobar>();
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message);
 Console.WriteLine(ex.StackTrace);
 }
 });
 return Ok();
 }
}

在運行該應用程序后,我們利用瀏覽器采用根路徑(“/”)對Action方法Index發起訪問后,服務端控制臺上會出現如下所示的錯誤信息。

ASP.NET Core 3框架揭秘之 異步線程無法使用IServiceProvider問題

 

二、ApplicationServices與RequestServices

 

從上圖所示的錯誤消息可以看出,問題出在我們試圖利用一個被Dispose的IServiceProvider來獲取我們所需的服務實例。我們知道,ASP.NET Core應用在啟動和請求處理過程中所需的服務幾乎都是由代表DI容器的IServiceProvider提供的。具體來說,這里存在著兩種類型的IServiceProvider對象,一種與當前應用的生命周期保持一致,我們一般將其稱為ApplicationServices,另一種則是具體針對每個請求的IServiceProvider對象,我們將其稱為RequestServices。

一般來說,ApplicationServices用于提供管道構建過程中所需的服務實例,具體請求處理過程中所需的服務實例一般由RequestServices提供。具體來說,對于接收的每一個請求,ASP.NET Core框架都會利用ApplicationServices創建一個代表服務范圍的IServiceScope對象,后者就是對RequestServices的封裝。在完成了針對請求的處理之后,服務范圍被終結,RequestServices被Dispose。

對于我們演示的實例來說,注入到HomeController構造函數中的IServiceProvider是RequestServices,由于針對RequestServices的使用是在另一個后臺線程中執行的,并且在使用的時候針對當前請求的處理已經結束(因為我們人為等待了100毫秒),自然就會出現上圖所示的異常。

 

三、如何獲取ApplicationServices

 

既然與請求綁定的RequestServices不能用,我們只能使用與應用綁定的ApplicationServices,那么后者如何得到呢?ASP.NET Core 3采用了基于IHost/IHostBuilder的承載方式,表示宿主的IHost接口具有如下所示的Services屬性,它返回的正式我們所需的ApplicationServices。

?
1
2
3
4
5
6
7
public interface IHost : IDisposable
{
 Task StartAsync(CancellationToken cancellationToken = new CancellationToken());
 Task StopAsync(CancellationToken cancellationToken = new CancellationToken());
 
 IServiceProvider Services { get; }
}

對于我們演示的程序來說,我們可以采用如下的方式在HomeController的構造中注入IHost服務的方式間接地獲得這個ApplicationServices對象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class HomeController: Controller
{
 private readonly IServiceProvider _applicationServices;
 public HomeController(IHost host)
 {
 _applicationServices = host.Services;
 }
 [HttpGet("/")]
 public IActionResult Index()
 {
 Task.Run(async() => {
 try
 {
 await Task.Delay(100);
 var foobar = _applicationServices.GetRequiredService<IFoobar>();
 }
 catch (Exception ex)
 {
 Console.WriteLine(ex.Message);
 Console.WriteLine(ex.StackTrace);
 }
 });
 return Ok();
 }
}

當我們采用如上的方式將RequestServices替換成ApplicationServices之后,我們的問題是否就解決了呢?在采用上面相同的方式進行測試之后,我們會發現服務端控制臺上出現了如下所示的錯誤消息。

ASP.NET Core 3框架揭秘之 異步線程無法使用IServiceProvider問題

 

四、服務實例的生命周期

 

上面的問題是由我們試圖利用一個代表“根容器”的IServiceProvider對象去解析一個生命周期模式為Scoped服務實例導致,具體的原因在《依賴注入[8]:服務實例的生命周期》已經講得很清楚了。為了解決這個問題,我們應該根據ApplicationServices創建一個“服務范圍”,并在該服務范圍內提取我們所需的服務實例。為了確保服務實例能夠被正?;厥?,我們還應該將代表服務范圍的IServiceScope對象及時終結掉。如下所示的是正確的編程方式。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class HomeController: Controller
{
 private readonly IServiceProvider _applicationServices;
 public HomeController(IHost host)
 {
 _applicationServices = host.Services;
 }
 [HttpGet("/")]
 public IActionResult Index()
 {
 Task.Run(async() => {
 await Task.Delay(100);
 using (var scope = _applicationServices.CreateScope())
 {
 var foobar = scope.ServiceProvider.GetRequiredService<IFoobar>();
 }
 });
 return Ok();
 }
}

 

五、統一的解決方案

 

之前我們將問題的解決方案落實在如何獲取與當前應用具有相同生命周期的ApplicationServices上,所以我們采用注入IHost的方式得到這個ApplicationServices。如果采用傳統的基于IWebHost/IWebHostBuilder的承載方式,IHost自然是獲取不到了。但是我們是真的需要這個ApplicationServices對象嗎?其實不是,我們真正需要的是利用它創建一個代表服務范圍的IServiceScope對象,并在該范圍內消費我們所需的服務實例。由于IServiceScope是通過IServiceScopeFactory創建的,所以我們只需要注入IServiceScopeFactory即可。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class HomeController : Controller
{
 private readonly IServiceScopeFactory _serviceScopeFactory;
 
 public HomeController(IServiceScopeFactory serviceScopeFactory)
 {
 _serviceScopeFactory = serviceScopeFactory;
 }
 
 [HttpGet("/")]
 public IActionResult Index()
 {
 Task.Run(async () =>
 {
 await Task.Delay(100);
 using (var scope = _serviceScopeFactory.CreateScope())
 {
 var foobar = scope.ServiceProvider.GetRequiredService<IFoobar>();
 }
 });
 return Ok();
 }
}

總結

以上所述是小編給大家介紹的ASP.NET Core 3框架揭秘之 異步線程無法使用IServiceProvider問題,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
如果你覺得本文對你有幫助,歡迎轉載,煩請注明出處,謝謝!

原文鏈接:https://www.cnblogs.com/artech/p/async-di.html

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 精品国产一区二区三区忘忧草 | 欧美.com | 欧美精品久久 | 一区二区三区在线播放 | 国产淫片在线观看 | 成人乱人乱一区二区三区 | 一级特黄av | 日精品 | 黄色电影天堂 | 欧美一级全黄 | 日韩精品在线视频 | 亚洲成人免费 | 国产视频二 | 精久久| 亚洲免费视频网 | 3d动漫精品一区二区三区 | 日韩二区 | 亚洲自拍偷拍精品视频 | 亚洲一区二区久久 | 亚洲免费网站 | 成人在线天堂 | 一区二区三区无码高清视频 | 国产成人久久精品一区二区三区 | 免费观看日韩一级片 | 午夜电影网| 久久99精品国产麻豆婷婷洗澡 | 一级特黄录像免费播放全99 | 国产目拍亚洲精品99久久精品 | 国产片在线观看 | 亚洲三级在线免费观看 | 精品日韩一区 | 国产精品第一国产精品 | 日本不卡免费一区二区三区综合久久 | 91综合网 | av在线精品 | 一区二区三区在线免费观看 | 国产精品中文字幕在线 | 亚洲一区二区三区视频 | 欧美日韩在线电影 | 九九热在线视频观看这里只有精品 | 毛片区|