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

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

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

服務器之家 - 編程語言 - ASP.NET教程 - DotNetCore深入了解之HttpClientFactory類詳解

DotNetCore深入了解之HttpClientFactory類詳解

2020-06-08 15:23李志章 ASP.NET教程

這篇文章主要給大家介紹了關于DotNetCore深入了解之HttpClientFactory類的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧

當需要向某特定URL地址發送HTTP請求并得到相應響應時,通常會用到HttpClient類。該類包含了眾多有用的方法,可以滿足絕大多數的需求。但是如果對其使用不當時,可能會出現意想不到的事情。

?
1
using(var client = new HttpClient())

對象所占用資源應該確保及時被釋放掉,但是,對于網絡連接而言,這是錯誤的。

原因有二,網絡連接是需要耗費一定時間的,頻繁開啟與關閉連接,性能會受影響;再者,開啟網絡連接時會占用底層socket資源,但在HttpClient調用其本身的Dispose方法時,并不能立刻釋放該資源,這意味著你的程序可能會因為耗盡連接資源而產生預期之外的異常。

所以比較好的解決方法是延長HttpClient對象的使用壽命,比如對其建一個靜態的對象:

?
1
private static HttpClient Client = new HttpClient();

但從程序員的角度來看,這樣的代碼或許不夠優雅。

所以在.NET Core 2.1中引入了新的HttpClientFactory類。

它的用法很簡單,首先是對其進行IoC的注冊:

?
1
2
3
4
5
public void ConfigureServices(IServiceCollection services)
{
 services.AddHttpClient();
 services.AddMvc();
}

然后通過IHttpClientFactory創建一個HttpClient對象,之后的操作如舊,但不需要擔心其內部資源的釋放:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class LzzDemoController : Controller
{
 IHttpClientFactory _httpClientFactory;
 
 public LzzDemoController(IHttpClientFactory httpClientFactory)
 {
  _httpClientFactory = httpClientFactory;
 }
 
 public IActionResult Index()
 {
  var client = _httpClientFactory.CreateClient();
  var result = client.GetStringAsync("http://myurl/");
  return View();
 }
}

AddHttpClient的源碼:

?
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
27
28
public static IServiceCollection AddHttpClient(this IServiceCollection services)
{
 if (services == null)
 {
  throw new ArgumentNullException(nameof(services));
 }
 
 services.AddLogging();
 services.AddOptions();
 
 //
 // Core abstractions
 //
 services.TryAddTransient<HttpMessageHandlerBuilder, DefaultHttpMessageHandlerBuilder>();
 services.TryAddSingleton<IHttpClientFactory, DefaultHttpClientFactory>();
 
 //
 // Typed Clients
 //
 services.TryAdd(ServiceDescriptor.Singleton(typeof(ITypedHttpClientFactory<>), typeof(DefaultTypedHttpClientFactory<>)));
 
 //
 // Misc infrastructure
 //
 services.TryAddEnumerable(ServiceDescriptor.Singleton<IHttpMessageHandlerBuilderFilter, LoggingHttpMessageHandlerBuilderFilter>());
 
 return services;
}

它的內部為IHttpClientFactory接口綁定了DefaultHttpClientFactory類。

再看IHttpClientFactory接口中關鍵的CreateClient方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public HttpClient CreateClient(string name)
{
 if (name == null)
 {
  throw new ArgumentNullException(nameof(name));
 }
 
 var entry = _activeHandlers.GetOrAdd(name, _entryFactory).Value;
 var client = new HttpClient(entry.Handler, disposeHandler: false);
 
 StartHandlerEntryTimer(entry);
 
 var options = _optionsMonitor.Get(name);
 for (var i = 0; i < options.HttpClientActions.Count; i++)
 {
  options.HttpClientActions[i](client);
 }
 
 return client;
}

HttpClient的創建不再是簡單的new HttpClient(),而是傳入了兩個參數:HttpMessageHandler handler與bool disposeHandler。disposeHandler參數為false值時表示要重用內部的handler對象。handler參數則從上一句的代碼可以看出是以name為鍵值從一字典中取出,又因為DefaultHttpClientFactory類是通過TryAddSingleton方法注冊的,也就意味著其為單例,那么這個內部字典便是唯一的,每個鍵值對應的ActiveHandlerTrackingEntry對象也是唯一,該對象內部中包含著handler。

下一句代碼StartHandlerEntryTimer(entry); 開啟了ActiveHandlerTrackingEntry對象的過期計時處理。默認過期時間是2分鐘。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
internal void ExpiryTimer_Tick(object state)
{
 var active = (ActiveHandlerTrackingEntry)state;
 
 // The timer callback should be the only one removing from the active collection. If we can't find
 // our entry in the collection, then this is a bug.
 var removed = _activeHandlers.TryRemove(active.Name, out var found);
 Debug.Assert(removed, "Entry not found. We should always be able to remove the entry");
 Debug.Assert(object.ReferenceEquals(active, found.Value), "Different entry found. The entry should not have been replaced");
 
 // At this point the handler is no longer 'active' and will not be handed out to any new clients.
 // However we haven't dropped our strong reference to the handler, so we can't yet determine if
 // there are still any other outstanding references (we know there is at least one).
 //
 // We use a different state object to track expired handlers. This allows any other thread that acquired
 // the 'active' entry to use it without safety problems.
 var expired = new ExpiredHandlerTrackingEntry(active);
 _expiredHandlers.Enqueue(expired);
 
 Log.HandlerExpired(_logger, active.Name, active.Lifetime);
 
 StartCleanupTimer();
}

先是將ActiveHandlerTrackingEntry對象傳入新的ExpiredHandlerTrackingEntry對象。

?
1
2
3
4
5
6
7
public ExpiredHandlerTrackingEntry(ActiveHandlerTrackingEntry other)
{
 Name = other.Name;
 
 _livenessTracker = new WeakReference(other.Handler);
 InnerHandler = other.Handler.InnerHandler;
}

在其構造方法內部,handler對象通過弱引用方式關聯著,不會影響其被GC釋放。

然后新建的ExpiredHandlerTrackingEntry對象被放入專用的隊列。

最后開始清理工作,定時器的時間間隔設定為每10秒一次。

?
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
internal void CleanupTimer_Tick(object state)
{
 // Stop any pending timers, we'll restart the timer if there's anything left to process after cleanup.
 //
 // With the scheme we're using it's possible we could end up with some redundant cleanup operations.
 // This is expected and fine.
 //
 // An alternative would be to take a lock during the whole cleanup process. This isn't ideal because it
 // would result in threads executing ExpiryTimer_Tick as they would need to block on cleanup to figure out
 // whether we need to start the timer.
 StopCleanupTimer();
 
 try
 {
  if (!Monitor.TryEnter(_cleanupActiveLock))
  {
   // We don't want to run a concurrent cleanup cycle. This can happen if the cleanup cycle takes
   // a long time for some reason. Since we're running user code inside Dispose, it's definitely
   // possible.
   //
   // If we end up in that position, just make sure the timer gets started again. It should be cheap
   // to run a 'no-op' cleanup.
   StartCleanupTimer();
   return;
  }
 
  var initialCount = _expiredHandlers.Count;
  Log.CleanupCycleStart(_logger, initialCount);
 
  var stopwatch = ValueStopwatch.StartNew();
 
  var disposedCount = 0;
  for (var i = 0; i < initialCount; i++)
  {
   // Since we're the only one removing from _expired, TryDequeue must always succeed.
   _expiredHandlers.TryDequeue(out var entry);
   Debug.Assert(entry != null, "Entry was null, we should always get an entry back from TryDequeue");
 
   if (entry.CanDispose)
   {
    try
    {
     entry.InnerHandler.Dispose();
     disposedCount++;
    }
    catch (Exception ex)
    {
     Log.CleanupItemFailed(_logger, entry.Name, ex);
    }
   }
   else
   {
    // If the entry is still live, put it back in the queue so we can process it
    // during the next cleanup cycle.
    _expiredHandlers.Enqueue(entry);
   }
  }
 
  Log.CleanupCycleEnd(_logger, stopwatch.GetElapsedTime(), disposedCount, _expiredHandlers.Count);
 }
 finally
 {
  Monitor.Exit(_cleanupActiveLock);
 }
 
 // We didn't totally empty the cleanup queue, try again later.
 if (_expiredHandlers.Count > 0)
 {
  StartCleanupTimer();
 }
}

上述方法核心是判斷是否handler對象已經被GC,如果是的話,則釋放其內部資源,即網絡連接。

回到最初創建HttpClient的代碼,會發現并沒有傳入任何name參數值。這是得益于HttpClientFactoryExtensions類的擴展方法。

?
1
2
3
4
5
6
7
8
9
public static HttpClient CreateClient(this IHttpClientFactory factory)
{
 if (factory == null)
 {
  throw new ArgumentNullException(nameof(factory));
 }
 
 return factory.CreateClient(Options.DefaultName);
}

Options.DefaultName的值為string.Empty。

DefaultHttpClientFactory缺少無參數的構造方法,唯一的構造方法需要傳入多個參數,這也意味著構建它時需要依賴其它一些類,所以目前只適用于在ASP.NET程序中使用,還無法應用到諸如控制臺一類的程序,希望之后官方能夠對其繼續增強,使得應用范圍變得更廣。

?
1
2
3
4
5
public DefaultHttpClientFactory(
 IServiceProvider services,
 ILoggerFactory loggerFactory,
 IOptionsMonitor<HttpClientFactoryOptions> optionsMonitor,
 IEnumerable<IHttpMessageHandlerBuilderFilter> filters)

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://www.cnblogs.com/lizhizhang/p/9502862.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
主站蜘蛛池模板: 久久久久久久99 | 色综合88 | 成人免费毛片高清视频 | 99在线观看 | 久久综合一区二区 | 精品久久久久久久久久久 | 欧洲精品 | 不卡一二区 | 国产精品成av人在线视午夜片 | 国产精品久久影院 | 欧美xo影院 | 精品久久久久久久久久 | 久久国| 成人黄色av| 亚洲国产高清在线 | 国产精品美乳一区二区免费 | www国产网站| 中文字幕国产 | 精品一区二区三区免费视频 | 69中文字幕 | 久久精品91久久久久久再现 | 国产噜噜噜噜噜久久久久久久久 | 国产一区中文字幕 | 成人国产精品久久久 | www久草 | 精品成人| 国产免费一区二区三区最新6 | zzzzyyyy精品国产 | 亚洲成人高清在线 | 一级片在线观看 | 亚洲欧美激情精品一区二区 | 一区二区久久 | 亚洲天堂一区在线 | 欧美精品久久久久久久久老牛影院 | 欧美精品亚洲精品日韩精品 | 久久人人爽人人爽人人片av不 | 国产午夜精品久久久久久久 | 国产高清无密码一区二区三区 | 久久久久久免费精品 | 久久久精品影院 | 久久综合九九 |