C# 导致输出混乱的MVC 3压缩过滤器

C# 导致输出混乱的MVC 3压缩过滤器,c#,asp.net-mvc,action-filter,C#,Asp.net Mvc,Action Filter,因此,我有一个名为CompressAttribute的自定义属性,它在global.asax中设置为全局过滤器。它使用反射来检查当前操作方法的返回类型,如果是“ViewResult”,则使用GZip或Deflate压缩输出。它工作正常,除非页面抛出500服务器错误。如果遇到错误,我不会显示.NET错误页面,而是会看到以下内容: ��������`我�%&/M�{J�J��T�� 显然,它试图对500服务器错误页面进行编码,这会导致问题。处理这个问题的最佳方法是什么 以下是筛选代码: public

因此,我有一个名为CompressAttribute的自定义属性,它在global.asax中设置为全局过滤器。它使用反射来检查当前操作方法的返回类型,如果是“ViewResult”,则使用GZip或Deflate压缩输出。它工作正常,除非页面抛出500服务器错误。如果遇到错误,我不会显示.NET错误页面,而是会看到以下内容:

��������`我�%&/M�{J�J��T��

显然,它试图对500服务器错误页面进行编码,这会导致问题。处理这个问题的最佳方法是什么

以下是筛选代码:

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

好的,我可以通过清除应用程序错误事件中的Response.Filter属性来解决这个问题:

public void Application_Error(object sender, EventArgs e)
{
    Response.Filter.Dispose();
}

想知道是否有更正确的方法来实现这一点…

我在asp.net mvc 1.0中遇到了同样的问题,我浏览了一个包含渲染的页面(来自futures assembly)。显然,问题是响应被编码了两次。我必须为此子操作创建一个操作筛选器,以便在RouteData的DataTokens集合中设置一个标志。然后我必须修改压缩筛选器,以便在设置标志时返回。我还必须处理筛选器的执行顺序。可能这有助于验证在出现错误页面时是否多次调用压缩筛选器。

您也可以通过附加到
OnResultExecuting
而不是
OnActionExecuting
来解决此问题。这提供了一些优点

  • 你可以发现行动的结果,而无需诉诸反思
  • 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.
            }
        }
    
    公共密封类MyAttribute:ActionFilterAttribute
    {
    /// 
    ///在执行结果(通常是视图)之前由MVC调用。
    /// 
    /// 
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
    var result=filterContext.result;
    如果(结果为ViewResultBase)
    {
    var response=filterContext.HttpContext.response;
    //检查您的请求参数并附加筛选器。
    }
    }
    
    如果输出中已写入任何内容,则接受的答案将不起作用

    您可以确保头被保留在适当的位置,而不是处理筛选器:

     protected void Application_PreSendRequestHeaders()
    {
        // ensure that if GZip/Deflate Encoding is applied that headers are set
        // also works when error occurs if filters are still active
        HttpResponse response = HttpContext.Current.Response;
        if (response.Filter is GZipStream && response.Headers["Content-encoding"] != "gzip")
            response.AppendHeader("Content-encoding", "gzip");
        else if (response.Filter is DeflateStream && response.Headers["Content-encoding"] != "deflate")
            response.AppendHeader("Content-encoding", "deflate");
    }
    

    这并不能真正解决这个问题。我需要在调试期间能够看到异常信息、堆栈跟踪信息等。这并不意味着你不能使用
    HandleError
    属性来完成。谢谢!我们在IIS 7和7.5中出现此错误已经有一段时间了,并且想知道为什么。这不会发生在IIS 6或Cassino上。你的解决方案是n解决了这个问题。这是一个很好的解决方案。
    Dispose()
    似乎比设置
    Response更“正确”。Filter
    设置为
    null
    。还消除了以后每次进入调试模式的时间。这对我来说很有效。错误时会清除标题,这确保发送正确的内容标题。