HttpClient周りの仕様が変わってました
Xamarinから.NET 6+(MAUI含む)へ移行する際に注意すべきHTTPスタックのお話です。
HttpClientの挙動に影響するので、.NET 6+へ移行したらHTTP通信周りに異常が無いかテストしましょう!
HTTP Handlerの設定
.NET 6+になってHTTP Handler周りの仕様がXamarin.iOS / Androidの頃と変わりました。
Xamarin時代ではプロジェクト設定の↓こういうところにいたやつです。
Xamarinの場合
アプリプロジェクトでHttpClientが規定で使用するHttpMessageHandlerの実装を指定します。 Android/iOSのHTTPスタックのいずれか、Managed(.NET由来の実装)から選択可能です。
実装的には HttpClient
を引数無しで初期化する場合に影響します。
.NET 6+の場合
アプリプロジェクトの UseNativeHttpHandler
という設定が新しくできました。
- true: Android/iOS 用の HttpMessageHandler を使用します。
- false: Managed(.NET由来の実装)を使用します。
実装的には HttpClientHandler
を使用する場合に影響します。
HttpClientHandler
は.NET版とネイティブ版両方のHTTPスタックのラッパーのような立ち位置になり、UseNativeHttpHandler
の値によって挙動を切り替えます。
HttpClient
を引数無しで初期化した場合は HttpClientHandler
が使用されるようになっているため、こちらにも影響します。
HttpClient初期化方法による違い
Xamarinの場合
引数で任意のHttpMessageHandler実装を与えればHTTPスタックをコントロールできます。
.NET 6+の場合
UseNativeHttpHandlerがtrueの場合、基本的に.NETのHTTPスタックを使う道が無くなります。
ライブラリを作る場合の注意
UseNativeHttpHandler
はアプリビルド時の設定なのでライブラリでは制御する事が出来ません。
.NET版のHttpMessageHandler実装を期待して HttpClientHandler
を使用していた場合、ネイティブHttp Handlerが使われても動作するように修正するか、独自に.NET版のHttpMessageHandler実装を用意する必要があります。
例えば、iOSでUseNativeHttpHandlerがtrueの場合、HttpClientHandler.Proxyのセッターを呼び出すと例外が発生します。
実行時にUseNativeHttpHandlerの値を取得する
次のようなコードでアプリビルド時に設定されたUseNativeHttpHandlerの値を取得する事ができます。
System.AppContext.TryGetSwitch("System.Net.Http.UseNativeHttpHandler", out bool isNativeHttpHandlerEnabled);
参考
iOS, Androidで動作する場合のHttpClientHandlerクラスのソースコード - https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs - https://github.com/dotnet/runtime/blob/main/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs
iOSで使用されるネイティブ版HttpHandlerのソースコード - https://github.com/xamarin/xamarin-macios/blob/main/src/Foundation/NSUrlSessionHandler.cs
Androidで使用されるネイティブ版HttpHandlerのソースコード - https://github.com/xamarin/xamarin-android/blob/main/src/Mono.Android/Xamarin.Android.Net/AndroidMessageHandler.cs