知識マップ: HttpClientをusingで囲んではいけない ── C#業務アプリのHTTP通信実務(生成パターン・タイムアウト・リトライ)
記事「HttpClientをusingで囲んではいけない ── C#業務アプリのHTTP通信実務(生成パターン・タイムアウト・リトライ)」の主張を、概念と関係(エッジ)に分解した知識グラフの全体です。各関係には根拠・確認日・確度が付いています。
C#のHttpClientはリクエストごとにusingで生成・破棄すると、閉じたソケットがTIME_WAIT状態でポートを占有し続けソケット枯渇を招き、逆にstaticのまま固定するとDNSを接続作成時にしか解決せず接続先の変更に追従できなくなる。公式の解決策は、SocketsHttpHandlerのPooledConnectionLifetimeで接続の寿命を区切るか、DIを使うならIHttpClientFactoryにハンドラーの管理を任せ、既定2分ごとに入れ替えて両方の問題を防ぐことである。ただしCookieContainerが意図せず共有される副作用があり、SocketsHttpHandlerが使えない.NET FrameworkではIHttpClientFactory導入かServicePoint.ConnectionLeaseTimeoutでの折衷策が必要になる。既定100秒のタイムアウトは接続先ごとに明示し、リトライは標準のresilienceハンドラーに任せつつ二重登録になり得るメソッドは無効化する。
flowchart LR
accTitle: C# HttpClientの正しい持ち方の知識マップ
accDescr: HttpClientを毎回生成・破棄するとソケット枯渇を招き、staticのまま固定するとDNS変更に追従できなくなること、SocketsHttpHandlerのPooledConnectionLifetimeとIHttpClientFactoryがそれぞれ公式の解決策であること、タイムアウトとリトライの設計指針を示す図
httpclient["HttpClient"]
ihttpclientfactory["IHttpClientFactory"]
socketshttphandler["SocketsHttpHandler"]
per_request_httpclient_disposal["リクエストごとのHttpClient生成・破棄"]
tcp_time_wait["TCPのTIME-WAIT状態"]
ephemeral_port["エフェメラルポート(動的ポート)"]
socket_exhaustion["ソケット枯渇"]
dns_change_non_tracking["static HttpClientのDNS変更への非追従"]
pooled_connection_lifetime["PooledConnectionLifetime"]
dotnet_framework[".NET Framework"]
servicepoint_connectionleasetimeout["ServicePoint.ConnectionLeaseTimeout"]
httpclient_timeout["HttpClient.Timeoutプロパティ"]
cancellationtoken_dotnet["CancellationToken(.NET)"]
http_resilience_handler["Microsoft.Extensions.Http.Resilience 標準ハンドラー"]
retry_unsafe_methods_risk["安全でないHTTPメソッドの既定リトライによる二重実行リスク"]
proxy_auto_detection["プロキシの自動検出"]
legacy_http_api["WebClient/HttpWebRequest(レガシーHTTP API)"]
cookiecontainer_sharing_risk["CookieContainerの意図しない共有"]
dotnet[".NET(Core以降)"]
httpclient -->|"利用する"| socketshttphandler
per_request_httpclient_disposal -->|"原因になり得る"| tcp_time_wait
tcp_time_wait -->|"利用する"| ephemeral_port
tcp_time_wait -.->|"原因になり得る"| socket_exhaustion
ihttpclientfactory -->|"軽減する"| socket_exhaustion
ihttpclientfactory -.->|"防止する"| dns_change_non_tracking
pooled_connection_lifetime -->|"防止する"| dns_change_non_tracking
socketshttphandler -->|"で構成できる"| pooled_connection_lifetime
socketshttphandler -->|"両立しない"| dotnet_framework
ihttpclientfactory -->|"推奨される対応"| dotnet_framework
servicepoint_connectionleasetimeout -.->|"防止する"| dns_change_non_tracking
httpclient -->|"で構成できる"| httpclient_timeout
httpclient -->|"利用する"| cancellationtoken_dotnet
ihttpclientfactory -.->|"利用する"| http_resilience_handler
http_resilience_handler -.->|"原因になり得る"| retry_unsafe_methods_risk
httpclient -.->|"利用する"| proxy_auto_detection
httpclient -->|"の後継"| legacy_http_api
ihttpclientfactory -.->|"原因になり得る"| cookiecontainer_sharing_risk
socketshttphandler -->|"前提とする"| dotnet
概念間の関係(全19件)
図と同じ関係を文章でも列挙します。表示している文と機械可読な意味データ(RDFa)は同じ要素に載っています。確度が「確立した関係」のものは直接の関係として、「条件付きの関係」のものは成立条件つきの言明(rdf:Statement)として表現しています。
- HttpClientはSocketsHttpHandlerを利用します。
- リクエストごとのHttpClient生成・破棄はTCPのTIME-WAIT状態の原因になることがあります。
- TCPのTIME-WAIT状態はエフェメラルポート(動的ポート)を利用します。
- TCPのTIME-WAIT状態はソケット枯渇の原因になることがあります。
- IHttpClientFactoryはソケット枯渇を軽減します。
- IHttpClientFactoryはstatic HttpClientのDNS変更への非追従を防ぎます。
- PooledConnectionLifetimeはstatic HttpClientのDNS変更への非追従を防ぎます。
- SocketsHttpHandlerはPooledConnectionLifetimeで構成できます。
- SocketsHttpHandlerは.NET Frameworkと両立しません。
- IHttpClientFactoryは.NET Frameworkに対する本記事の推奨です。
- ServicePoint.ConnectionLeaseTimeoutはstatic HttpClientのDNS変更への非追従を防ぎます。
- HttpClientはHttpClient.Timeoutプロパティで構成できます。
- HttpClientはCancellationToken(.NET)を利用します。
- IHttpClientFactoryはMicrosoft.Extensions.Http.Resilience 標準ハンドラーを利用します。
- Microsoft.Extensions.Http.Resilience 標準ハンドラーは安全でないHTTPメソッドの既定リトライによる二重実行リスクの原因になることがあります。
- HttpClientはプロキシの自動検出を利用します。
- HttpClientはWebClient/HttpWebRequest(レガシーHTTP API)の後継に当たります。
- IHttpClientFactoryはCookieContainerの意図しない共有の原因になることがあります。
- SocketsHttpHandlerは.NET(Core以降)を前提とします。
主要概念の定義
機械可読データ
このページはサイトの知識グラフ(_data/knowledge/)から自動生成されています。誤りの指摘はお問い合わせからお願いします。