私の目標は、AuthorizationFilter または DelegatingHandler を使用して Web API リクエストを認証することです。リクエスト本文を含め、いくつかの場所でクライアント ID と認証トークンを探したいと考えています。最初はこれが簡単に思えた、私はこのようなことをすることができました
var task = _message.Content.ReadAsAsync<Credentials>();
task.Wait();
if (task.Result != null)
{
// check if credentials are valid
}
問題は、HttpContent を 1 回しか読み取れないことです。これを Handler または Filter で行うと、アクション メソッドでコンテンツを利用できなくなります。私はいくつかの回答をStackOverflowで見つけました. これは、フィルターまたはハンドラーでクールな Web API コンテンツ解析コードを使用することを妨げる、かなり厳しい制限のように思えます。
技術的な制限ですか?私が見ていない非常に悪いことをしないようにしようとしているのですか?
死後:
フィリップが提案したように、ソースを調べました。ReadAsStreamAsync は内部ストリームを返し、ストリームがサポートしている場合はSeek を呼び出すことを妨げるものは何もありません。私のテストでは、ReadAsAsync を呼び出した場合、次のようにしました。
message.Content.ReadAsStreamAsync().ContinueWith(t => t.Result.Seek(0, SeekOrigin.Begin)).Wait();
自動モデル バインディング プロセスは、アクション メソッドにヒットすると正常に動作します。私はこれを使用しませんでしたが、より直接的なものを選択しました:
var buffer = new MemoryStream(_message.Content.ReadAsByteArrayAsync().WaitFor());
var formatters = _message.GetConfiguration().Formatters;
var reader = formatters.FindReader(typeof(Credentials), _message.Content.Headers.ContentType);
var credentials = reader.ReadFromStreamAsync(typeof(Credentials), buffer, _message.Content, null).WaitFor() as Credentials;
拡張メソッドを使用 (私は await キーワードなしで .NET 4.0 を使用しています)
public static class TaskExtensions
{
public static T WaitFor<T>(this Task<T> task)
{
task.Wait();
if (task.IsCanceled) { throw new ApplicationException(); }
if (task.IsFaulted) { throw task.Exception; }
return task.Result;
}
}
最後のキャッチとして、HttpContent にはハードコードされた最大バッファー サイズがあります。
internal const int DefaultMaxBufferSize = 65536;
したがって、コンテンツがそれよりも大きくなる場合は、ReadAsByteArrayAsync を呼び出す前に、より大きなサイズで LoadIntoBufferAsync を手動で呼び出す必要があります。