2月第4週の振り返り

2月第4週(2/17-2/23)

ASP.NET Core MVC

不適切な操作でリソースが解放されないことが多いHttpClientの正しい利用方法を学んだ。定石であるusingステートメントではなく(実際のところusingを使わないところまで定石化しているらしいが)、DIコンテナでIHttpClientFactoryの実装を供給してもらい自分でCreateClient()する方法と、HttpClientを自分のサービスクラスに供給してもらいさらにそのサービスクラスインスタンスを必要な場所に供給してもらう方法とが紹介されていた。

前者はアクセス先のベースURI不定である場合に便利で、後者は同一ベースURIに複数のリクエストを送信する場合に便利である。

またアクセス先のAPIDoS扱いされないよう、リクエストが500エラーで失敗したらexponential backoffで再試行するように設定する必要があるといった場合に、後者では個々のHttpClientにその設定を施すことなくサービスクラスにあらかじめ設定を書き込んでおけばよい点でも優れている。

docs.microsoft.com

利用の方法は上記ドキュメントに記載されているが、流れとしては

  1. Controllerがサービスクラス実装の供給をインタフェースの形で受ける(AddHttpClient<IMyClient, MyClientImpl>();)
  2. そのサービスクラスはHttpClientの供給を受けている(AddHttpClientがこれも行う)
  3. Controllerはサービスクラスインスタンスに、実装されたメソッドの実行を指示する(_myClientInterface.GetDataFromExternalAPI();)
  4. サービスクラスは供給を受けたHttpClientを使ってHTTPリクエストを行う(_httpClient.SendAsync(request);)

となる。単体テストをする気がないのであれば1.で実装クラスを直接指定してもよい。個人的にはビルトインであるHttpClientのラッパーに過ぎないサービスクラスは単体テスト不要だと思うが、そのサービスクラスに依存するControllerの単体テストは書いておきたいと思った。

またHttpClientの使用にあたっては、Content-Typeヘッダを自由に設定できるわけではないことに注意する必要がある。FormUrlEncodedContent, StringContentなどをHttpRequestMessageのContentに設定しておけば自動的に対応するものが指定されるようだ。

このサービスクラスインジェクションを使ってついにプログラム中でトークJSONを取得しパースすることができた。

有効期限は時刻ではなく時間(秒)で渡されるため、トークン情報クラスのコンストラクタでDateTime.UtcNowを取得してAddSecondsで加算した時刻をユーザデータに移し替えようとしたが、加算が反映されておらずしばらく悩んでいた。デバッガでトークン情報クラスの中身をよく見たところ、直接アクセスするべきでないとしてprivateにしたint expire_inに値が入っていないことが分かった。これをpublic int expire_in { private get; set; }にすることで解決した。

しかしpublic setである以上、IntelliSenseにexpire_inが候補として表示されてしまうので完全とは言い難い。来週はこの解決策を探りつつ、セッションのKVS格納を進めていきたい。