2010-12-28 3 views
17

Итак, у меня есть настраиваемый атрибут CompressAttribute, который настроен как глобальный фильтр в global.asax. Он использует отражение для проверки типа возврата текущего метода действий, и если он «ViewResult», он сжимает выходные данные с помощью GZip или Deflate. Он отлично работает, если только страница не выдает 500 Server Error. Если возникла ошибка, вместо отображения страницы ошибок .NET, я получаю следующую информацию:MVC 3 фильтр сжатия, вызывающий искаженный вывод

`I % &/m {J J t

По-видимому, он пытается кодировать страницу с ошибкой 500 Server, которая вызывает проблемы. Каков наилучший способ справиться с этим?

Вот код фильтра:

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

ответ

21

Хорошо, так что я был в состоянии решить эту проблему, очистив свойство Response.Filter в случае Application_Error:

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

Хотите знать, если есть более правильный путь чтобы сделать это, хотя ...

+0

Вы могли бы попытаться создать страницу ошибки? –

+0

На самом деле это не решило бы проблему. Я должен иметь возможность видеть информацию об исключении, информацию о трассировке стека и т. Д. Во время отладки. – Scott

+0

Это не значит, что вы не можете этого сделать, используя атрибут «HandleError». –

1

У меня была такая же проблема в asp.net mvc 1.0 для просмотра страницы с RenderAction внутри (из сборки фьючерсов). По-видимому, проблема заключалась в том, что ответ дважды кодировался. Мне пришлось создать фильтр действий для этих дочерних действий, чтобы флаг был установлен в коллекции DataTokens RouteData. Затем мне пришлось модифицировать фильтр сжатия, чтобы он возвращался в случае установки флага. Мне также пришлось иметь дело с порядком выполнения фильтров. Возможно, это может помочь, проверьте, вызван ли фильтр сжатия более одного раза, когда страница с ошибкой поднята.

6

Вы можете решить это, установив 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. 
     } 
    } 
0

Принятая ответ не будет работать, если что-то было уже написано к выходу.

Вместо утилизации фильтра вы можете убедиться, что заголовки в настоящее время сохраняется на месте:

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"); 
} 
Смежные вопросы