Introduction
AWS の API Gateway の API を .NET から叩いた際、 Unable to write content to request stream; content would exceed Content-Length.
に遭遇した。
しかし、この現象に再現したメンバーとそうでないメンバーがいて、原因がわからなかった。
再現コードは、互いに「殆ど」似ていた。
違いは、出力するログの有無。
下記は上記の例外が出力するコード。
1 | using System; |
下記は実行例。
1 | dotnet run |
How to resolve?
問題は Console.WriteLine
の順序変更、あるいはログ出力をなくせばいい。
1 | Console.WriteLine($"{multipartFormDataContent.Headers.ContentLength}"); |
を下記に変更する。
1 | Console.WriteLine($"{byteArrayContent.Headers.ContentLength}"); |
1 | dotnet run |
ContentLength
のプロパティの出力が変わっている?
Why?
結論から言えば、.NET のバグである。
しかも、.NET Framework 4.5 から連綿と続くバグである。
‘Content-Length’ header not always returned when enumerating HttpContentHeaders #16162
コメントにあるように
An obvious solution is to adjust MultipartContent to explicitly set the Content-Length header to null before serializing all the parts to a stream, or when adding a part.
とある。
シリアライズ (この場合、リクエストを Stream に渡すこと) 前に Content-Length ヘッダーを初期化すればいいということだ。
.NET のソースを見ると、 ContentLength
にアクセスした瞬間に、マルチパート/フォーム データの HttpContent オブジェクトのコレクションがキャッシュされてしまうように見えるため、キャッシュをリセットすることで対処する。
つまり、下記のように一度 MultipartFormDataContent.Headers.ContentLength
を null で初期化すればいい。
1 | using System; |
1 | dotnet run |
一応、この問題対する Pull Request は提案されている Content-Length header is present in HttpContentHeaders
#33174 がマージされなかった。