WebApi输出缓存

时间:2013-06-24 14:49:13

标签: asp.net-web-api outputcache

我正在尝试在WebApi中实现一个输出缓存,它可以缓存已经过滤器处理的响应并生成格式化程序未处理的响应。

从我所见,ActionFilterAttribute的OnActionExecuting和OnActionExecuted在序列化格式化程序之前执行,因此如果缓存响应,则在缓存命中时,您将响应完全相同的内容,并且该内容将再次序列化为传输。

作为MVC中可能的解决方案,我认为您可以通过实现IResultFilter来实现这一点,该IResultFilter通过缓存序列化响应来覆盖OnResultExecuted。使用这种方法我不知道如何拦截请求处理以避免序列化格式化程序,我认为拦截的可能解决方案是创建一个自定义ActionResult,由IResultFilter直接处理。请注意,此解决方案不适合我,因为我正在WebApi应用程序中实现OutputCache。

1 个答案:

答案 0 :(得分:0)

在编写响应时,Web API中的格式化程序仅对类型为ObjectContent的HttpContents起作用。

在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;
        }
    }
}