1

フィルターによって既に処理された応答をキャッシュし、フォーマッターによって処理されない応答を生成できる出力キャッシュを WebApi に実装しようとしています。

私が見たものから、ActionFilterAttribute の OnActionExecuting と OnActionExecuted はシリアル化フォーマッタの前に実行されるため、応答をキャッシュすると、キャッシュ ヒットでまったく同じコンテンツが応答され、そのコンテンツは再度シリアル化されて送信されます。

MVC で可能な解決策として、シリアル化された応答をキャッシュすることで OnResultExecuted をオーバーライドする IResultFilter を実装することでこれを行うことができると思います。このアプローチでは、シリアライゼーション フォーマッタを回避するためにリクエスト処理をインターセプトする方法がわかりません。インターセプトの可能な解決策は、IResultFilter によって直接処理されるカスタム ActionResult を作成することだと思います。WebApi アプリケーションに OutputCache を実装しているため、このソリューションは私には適していないことに注意してください。

4

1 に答える 1

0

応答を書き込んでいる間、Web API のフォーマッターは、型の HttpContents に対してObjectContentのみ動作します。

OnActionExecuted メソッドでは、以下のようなことを行うことでシリアル化を強制的に実行し、応答コンテンツを次のStreamContentように設定できます (この方法では、フォーマッターが表示されません)。

以下に例を示します。

public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
    HttpResponseMessage response = actionExecutedContext.Response;

    if (response != null && response.IsSuccessStatusCode)
    {
        ObjectContent originalContent = response.Content as ObjectContent;

        if (originalContent != null)
        {
            MemoryStream ms = new MemoryStream();

            // NOTE:
            // 1. We are forcing serialization to occur into a buffered stream here
            // 2. This can cause exception. You can leave it as it is and Web API's exception handling mechanism should
            //    do the right thing.
            originalContent.CopyToAsync(ms).Wait();

            // reset the position
            ms.Position = 0;

            StreamContent newContent = new StreamContent(ms);

            // Copy the headers
            foreach (KeyValuePair<string, IEnumerable<string>> header in originalContent.Headers)
            {
                newContent.Headers.TryAddWithoutValidation(header.Key, header.Value);
            }

            //dispose the original content
            originalContent.Dispose();

            //TODO: cache this new httpcontent 'newContent' (so we are caching both serialized body + headers too)

            //Set the response
            //NOTE: This newContent will not hit the formatters
            actionExecutedContext.ActionContext.Response.Content = newContent;
        }
    }
}
于 2013-06-24T15:58:32.650 に答える