ぴーさんログ

だいたいXamarin.Formsのブログ

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