MVC 3压缩过滤器导致输出乱码

Sco*_*ott 17 c# asp.net-mvc action-filter

所以,我有一个名为CompressAttribute的自定义属性,它在global.asax中设置为全局过滤器.它使用反射来检查当前操作方法的返回类型,如果它是"ViewResult",它使用GZip或Deflate压缩输出.它工作得很好,除非页面抛出500服务器错误.如果遇到错误,而不是显示.NET错误页面,我得到一堆:

`我%/米{JJT

显然它正在尝试编码导致问题的500 Server Error页面.处理这个问题的最佳方法是什么?

这是过滤器代码:

public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            MethodInfo actionMethodInfo = Common.GetActionMethodInfo(filterContext);
            if (GetReturnType(actionMethodInfo).ToLower() != "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"))
            {
                response.AppendHeader("Content-encoding", "gzip");
                response.Filter = new WebCompressionStream(response.Filter, CompressionType.GZip);
            }
            else if (acceptEncoding.Contains("DEFLATE"))
            {
                response.AppendHeader("Content-encoding", "deflate");
                response.Filter = new WebCompressionStream(response.Filter, CompressionType.Deflate);
            }
        }
Run Code Online (Sandbox Code Playgroud)

Sco*_*ott 21

好的,我可以通过清除Application_Error事件中的Response.Filter属性来解决这个问题:

public void Application_Error(object sender, EventArgs e)
{
    Response.Filter.Dispose();
}
Run Code Online (Sandbox Code Playgroud)

想知道是否有更正确的方法来做到这一点......


小智 7

你也可以通过附加OnResultExecuting而不是来解决这个问题OnActionExecuting.这提供了一些优点

  1. 您无需借助反射即可发现动作结果.
  2. OnResultExecuting在特殊情况下不会执行(MVC会调用OnException但不会调用OnResultExecuting)

像这样的东西:

public sealed class MyAttribute  : ActionFilterAttribute
{
    /// <summary>
    /// Called by MVC just before the result (typically a view) is executing.
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var result = filterContext.Result;
        if (result is ViewResultBase)
        {
            var response = filterContext.HttpContext.Response;

            // Check your request parameters and attach filter.
        }
    }
Run Code Online (Sandbox Code Playgroud)