2010-12-28 13 views
17

Mam więc niestandardowy atrybut o nazwie CompressAttribute, który jest ustawiony jako globalny filtr w pliku global.asax. Używa refleksji do zbadania typu zwracanego przez bieżącą metodę akcji i jeśli jest to "ViewResult", kompresuje dane wyjściowe za pomocą GZip lub Deflate. Działa dobrze, z wyjątkiem sytuacji, gdy strona zgłasza błąd serwera 500. Jeśli napotkany zostanie błąd, zamiast wyświetlać stronę błędu .NET, otrzymuję masę tego:Filtr kompresji MVC 3 powodujący zniekształcone wyjście

`I % &/m {J J t

Podobno próbuje zakodować stronę błędu 500 serwera, która powoduje problemy. Jaki jest najlepszy sposób, aby sobie z tym poradzić?

Oto kod: Filtr

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

Odpowiedz

21

Ok, więc udało mi się rozwiązać ten problem poprzez wyczyszczenie własności Response.Filter w przypadku Application_Error:

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

Zastanawiasz się, czy istnieje bardziej poprawny sposób Zrobić to jednak ...

+0

można spróbować tworząc stronę błędu niestandardowego? –

+0

To naprawdę nie rozwiązałoby problemu. Podczas debugowania muszę być w stanie zobaczyć informacje o wyjątku, informacje śledzenia stosu itp. – Scott

+0

Nie oznacza to, że nie można tego zrobić za pomocą atrybutu 'HandleError'. –

1

Miałem ten sam problem w asp.net mvc 1.0 przeglądania strony, która miała RenderAction wewnątrz (od kontraktów futures). Najwyraźniej problem polegał na dwukrotnym zakodowaniu odpowiedzi. Musiałem utworzyć filtr akcji dla tych działań podrzędnych, aby ustawić flagę w kolekcji DataTokens w RouteData. Następnie musiałem zmodyfikować filtr kompresujący, aby powrócił w przypadku ustawienia flagi. Musiałem również poradzić sobie z kolejnością wykonywania filtrów. Może to może pomóc, sprawdzić, czy filtr kompresji jest wywoływany więcej niż jeden raz, gdy strona błędu jest podniesiona.

6

Można to również rozwiązać, dołączając do OnResultExecuting zamiast OnActionExecuting. Daje to kilka korzyści:

  1. Możesz odkryć efekt działania bez uciekania się do refleksji.
  2. OnResultExecuting nie będzie wykonywał w wyjątkowych przypadkach (MVC będzie wywoływał OnException ale nie OnResultExecuting)

coś takiego:

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

Zaakceptowanych odpowiedź nie będzie działać, jeśli wszystko zostało już napisane do wyjścia.

Zamiast usuwania filtra można upewnić się, że nagłówki są utrwalone w lokalu:

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