Asp.net mvc 我可以在ASP.NET MVC中使用[CompressFilter]而不中断圆环缓存吗

Asp.net mvc 我可以在ASP.NET MVC中使用[CompressFilter]而不中断圆环缓存吗,asp.net-mvc,caching,donut-caching,Asp.net Mvc,Caching,Donut Caching,我试图让[]使用甜甜圈缓存并遇到问题 结果是整个页面被缓存,而不仅仅是甜甜圈。下面是我正在使用的CompressFilter的源代码。我将其从更改为使用OnResultExecuted而不是OnActionExecuting(),因为我需要访问结果类型以避免缓存某些ActionResult子类 查看OutputCacheAttribute的实际MVC v1源代码,它似乎也在使用OnResultExecuted(),但我认为这一事实并不是直接导致冲突的原因 我对替换缓存的工作原理了解不够,无法完全

我试图让[]使用甜甜圈缓存并遇到问题

结果是整个页面被缓存,而不仅仅是甜甜圈。下面是我正在使用的
CompressFilter
的源代码。我将其从更改为使用
OnResultExecuted
而不是
OnActionExecuting()
,因为我需要访问结果类型以避免缓存某些ActionResult子类

查看
OutputCacheAttribute
的实际MVC v1源代码,它似乎也在使用
OnResultExecuted()
,但我认为这一事实并不是直接导致冲突的原因

我对替换缓存的工作原理了解不够,无法完全理解它为什么会这样做。我认为值得注意的是,尽管如此,这并不会导致任何形式的损坏显示。它的行为就像没有甜甜圈一样

看起来我必须使用某种IIs“插件”来处理缓存,我真的不想这么做,但看起来我也需要甜甜圈缓存

事实上,我现在更感兴趣的是知道它为什么会有这种效果,但如果可能的话,一个解决方案也会很好

public class CompressFilter : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        HttpRequestBase request = filterContext.HttpContext.Request;

        // dont encode images!
        if (filterContext.Result is ImageResult)
        {
            return;
        }

        string acceptEncoding = request.Headers["Accept-Encoding"];

        if (string.IsNullOrEmpty(acceptEncoding)) return;

        acceptEncoding = acceptEncoding.ToUpperInvariant();

        HttpResponseBase response = filterContext.HttpContext.Response;

        if (acceptEncoding.Contains("GZIP"))
        {
            response.AppendHeader("Content-encoding", "gzip");
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
        else if (acceptEncoding.Contains("DEFLATE"))
        {
            response.AppendHeader("Content-encoding", "deflate");
            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
        }
    }
}

我重写了OnResultExecuting方法。这是在呈现ActionResult之前调用的。在检查客户端是否接受压缩之前,我先检查要呈现的结果类型。如果它不是ViewResult,我不会应用任何类型的压缩

要使其工作,您的操作必须显式调用View()或PartialView()

以下是CompressOutputRTIBUTE的外观:

public class CompressOutputAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext) 
    {
        var result = filterContext.Result;
        if (!(result is ViewResult))
            return;

        HttpRequestBase request = filterContext.HttpContext.Request;
        string acceptEncoding = request.Headers["Accept-Encoding"];
        if (string.IsNullOrEmpty(acceptEncoding))
            return;

        acceptEncoding = acceptEncoding.ToUpperInvariant();

        HttpResponseBase response = filterContext.HttpContext.Response;
        if (acceptEncoding.Contains("GZIP"))
        {        
            // we want to use gzip 1st
            response.AppendHeader("Content-encoding", "gzip");
            //Add DeflateStream to the pipeline in order to compress response on the fly 
            response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
        }
        else if (acceptEncoding.Contains("DEFLATE"))
        {
            //If client accepts deflate, we'll always return compressed content 
            response.AppendHeader("Content-encoding", "deflate");
            //Add DeflateStream to the pipeline in order to compress response on the fly 
            response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
        }
    }
}
控制器内部:

[CompressOutput]
public class ArticleController : Controller

    public PartialViewResult MostPopular()
    {
        var viewModel = ArticleMostPopularViewModel();
        viewModel.Articles = CmsService.GetMostPopularArticles();
        return PartialView(viewModel);
    }

    public ViewResult Show(int id)
    {
        var viewModel = ArticleShowViewModel();
        viewModel.Article = CmsService.GetArticle(id);
        return View(viewModel);
    }
}

这是CompressFilter类的错误实现

请阅读:

我已经写了我自己的,将遵守基于上述文章的AcceptEncoding::

public class CompressFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpRequestBase request = filterContext.HttpContext.Request;

        string[] supported = new string[] { "gzip", "deflate" };

        IEnumerable<string> preferredOrder = new AcceptList(request.Headers["Accept-Encoding"], supported);

        string preferred = preferredOrder.FirstOrDefault();

        HttpResponseBase response = filterContext.HttpContext.Response;

        switch (preferred)
        {
            case "gzip":
                response.AppendHeader("Content-Encoding", "gzip");
                response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
                break;

            case "deflate":
                response.AppendHeader("Content-Encoding", "deflate");
                response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
                break;

            case "identity":
            default:
                break;
        }
    }
}

public class AcceptList : IEnumerable<string>
{
    Regex parser = new Regex(@"(?<name>[^;,\r\n]+)(?:;q=(?<value>[\d.]+))?", RegexOptions.Compiled);

    IEnumerable<string> encodings;

    public AcceptList(string acceptHeaderValue, IEnumerable<string> supportedEncodings)
    {
        List<KeyValuePair<string, float>> accepts = new List<KeyValuePair<string, float>>();

        if (!string.IsNullOrEmpty(acceptHeaderValue))
        {
            MatchCollection matches = parser.Matches(acceptHeaderValue);

            var values = from Match v in matches
                         where v.Success
                         select new
                         {
                             Name = v.Groups["name"].Value,
                             Value = v.Groups["value"].Value
                         };

            foreach (var value in values)
            {
                if (value.Name == "*")
                {
                    foreach (string encoding in supportedEncodings)
                    {
                        if (!accepts.Where(a => a.Key.ToUpperInvariant() == encoding.ToUpperInvariant()).Any())
                        {
                            accepts.Add(new KeyValuePair<string, float>(encoding, 1.0f));
                        }
                    }

                    continue;
                }

                float desired = 1.0f;
                if (!string.IsNullOrEmpty(value.Value))
                {
                    float.TryParse(value.Value, out desired);
                }

                if (desired == 0.0f)
                {
                    continue;
                }

                accepts.Add(new KeyValuePair<string, float>(value.Name, desired));
            }
        }

        this.encodings = from a in accepts
                         where supportedEncodings.Where(se => se.ToUpperInvariant() == a.Key.ToUpperInvariant()).Any() || a.Key.ToUpperInvariant() == "IDENTITY"
                         orderby a.Value descending
                         select a.Key;
    }

    IEnumerator<string> IEnumerable<string>.GetEnumerator()
    {
        return this.encodings.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable)this.encodings).GetEnumerator();
    }
}
公共类CompressFilter:ActionFilterAttribute
{
公共覆盖无效OnActionExecuting(ActionExecutingContext filterContext)
{
HttpRequestBase请求=filterContext.HttpContext.request;
支持的字符串[]=新字符串[]{“gzip”,“deflate”};
IEnumerable preferredOrder=新的AcceptList(请求头[“接受编码”],受支持);
string preferred=preferredOrder.FirstOrDefault();
HttpResponseBase response=filterContext.HttpContext.response;
开关(首选)
{
案例“gzip”:
AppendHeader(“内容编码”、“gzip”);
response.Filter=newgzipstream(response.Filter,CompressionMode.Compress);
打破
案例“deflate”:
AppendHeader(“内容编码”,“deflate”);
response.Filter=新的DeflateStream(response.Filter,CompressionMode.Compress);
打破
案例“身份”:
违约:
打破
}
}
}
公共类接受列表:IEnumerable
{
正则表达式解析器=新正则表达式(@“(?[^;,\r\n]+)(?:;q=(?[\d.]+))?”,RegexOptions.Compiled);
IEnumerable编码;
公共接受列表(字符串acceptHeaderValue,IEnumerable supportedEncodings)
{
列表接受=新列表();
如果(!string.IsNullOrEmpty(acceptHeaderValue))
{
MatchCollection matches=parser.matches(acceptHeaderValue);
var值=来自匹配项中的匹配项v
成功在哪里
选择新的
{
Name=v.Groups[“Name”].值,
值=v.Groups[“值”]。值
};
foreach(值中的var值)
{
如果(value.Name==“*”)
{
foreach(supportedEncodings中的字符串编码)
{
如果(!accepts.Where(a=>a.Key.ToUpperInvariant()==encoding.ToUpperInvariant()).Any())
{
接受.Add(新的KeyValuePair(编码,1.0f));
}
}
继续;
}
所需浮动=1.0f;
如果(!string.IsNullOrEmpty(value.value))
{
float.TryParse(value.value,超出所需值);
}
如果(需要==0.0f)
{
继续;
}
Add(新的KeyValuePair(value.Name,所需));
}
}
this.encodings=来自中的
where supportedEncodings.where(se=>se.ToUpperInvariant()==a.Key.ToUpperInvariant()).Any()| | a.Key.ToUpperInvariant()
orderby a.值递减
选择a.键;
}
IEnumerator IEnumerable.GetEnumerator()
{
返回此.encodings.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
返回((IEnumerable)this.encodings).GetEnumerator();
}
}

+1感谢您声明您已阅读了源代码。@jordan谢谢!我只是希望我没有花一个小时去弄明白愚蠢的[压缩过滤器]是什么冲突。我检查了所有其他可能导致甜甜圈缓存失败的原因,真希望这不是问题+1,因为它将我指向了这个有用的过滤器。谢谢不管具体的过滤器实现是什么,您都需要仔细检查是否没有通过调用RenderAction进行双重压缩,从而应用过滤器(基本控制器具有过滤器)。在我的实现中,我正在检查
是否(response.Filter是GZipStream | | response.Filter是DeflateStream)
,如果为true,则跳过过滤器的其余部分。谢谢。接受编码是唯一的区别吗?我现在没有时间比较它们。再次使用OnResultExecuting的thx+1。我发现