Help us understand the problem. What is going on with this article?

System.Net.HttpClientのDisposeは、不要なのか?

More than 5 years have passed since last update.

C# 4.0以降、非同期に対応した、むしろ非同期専用のSystem.Net.HttpClientクラスが提供されている。

非同期でHttp周りを扱うならHttpClientを使うのが筋だろう。
HttpClientは、非同期のみ対応している、当然ながら非同期処理のバックエンドは、Taskである。

ところで、HttpClientクラスは、IDisposableになっている。
TaskのDisposeは、WaitHandle使わない限り、まず不要であったが、
HttpClientは、どうだろうか?

調査

ILSpyでSystem.Net.HttpClientを覗いてみた。

HttpClientのDisposeメソッドは、次のようにオーバーライドされている。

protected override void Dispose(bool disposing)
{
    if (disposing && !this.disposed)
    {
        this.disposed = true;
        ServicePointManager.CloseConnectionGroups(this.connectionGroupName);
    }
    base.Dispose(disposing);
}

またHttpClientは、HttpMessageHandlerクラスから派生されていて、
HttpMessageHandlerクラスもIDisposableであるが、
HttpMessageHandlerのDisposeメソッドは、何もしていない。

如何にも怪しいのが、ServicePointManager.CloseConnectionGroupsだろう。

ServicePointManager.CloseConnectionGroups(this.connectionGroupName);

CloseConnectionGroupsメソッド

foreach (DictionaryEntry dictionaryEntry in ServicePointManager.s_ServicePointTable){
WeakReference weakReference = dictionaryEntry.Value as WeakReference;
    if (weakReference != null){
        ServicePoint servicePoint = (ServicePoint)weakReference.Target;
        if (servicePoint != null){
            servicePoint.CloseConnectionGroupInternal(connectionGroupName);
        }
    }
}

サービスポイントから削除するコードのようだ。
恐らくは、コネクションプールのようなものだと思われる。

検証

上記のコードからs_ServicePointTableフィールドを覗けば、何かわかるかも知れない。

ServicePointManager.MaxServicePointIdleTimeでアイドル時間を設定できる。
規定値では、100秒になっているが、検証で100秒も待てないので5秒ぐらいに設定しておく。

リフレクションでs_ServicePointTableを覗くようにして、検証する。

ServicePointManager.MaxServicePointIdleTime = 5000; // 5秒でサービスポイントから解除するように…

var getter = typeof(ServicePointManager).GetField( "s_ServicePointTable" , BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static );

HttpClient http = new HttpClient();
http.GetAsync( @"http://www.google.co.jp/" ).Wait();

var table = getter.GetValue( null ) as Hashtable; // s_ServicePointTable is Hashtable
Console.WriteLine( table.Count );    // 1
Thread.Sleep( 10000 );               // 10秒ぐらい待ってみる
Console.WriteLine( table.Count );    // 0

結論

HttpClientのインスタンスをわざわざDisposeしなくても、タイムアウトすれば勝手に破棄してくれるので、明示的にDisposeを呼ぶ必要はない。

Temarin
単なる趣味プログラミングの人
http://pitacorebox.webcrow.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away