2010-12-28 15 views
17

Quindi, ho un attributo personalizzato chiamato CompressAttribute che è impostato come un filtro globale in global.asax. Usa la riflessione per esaminare il tipo di ritorno del metodo di azione corrente e se è "ViewResult" comprime l'output usando GZip o Deflate. Funziona bene, tranne se una pagina genera un errore di 500 server. Se viene rilevato un errore, invece di visualizzare la pagina di errore .NET, ottengo un sacco di questo:Filtro di compressione MVC 3 che causa un'errata produzione

`I%% &/m {J J t

Apparentemente sta tentando di codificare la pagina Errore del server 500 che causa problemi. Qual è il modo migliore per gestire questo?

Ecco il codice del filtro:

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

risposta

21

Ok, quindi ero in grado di risolvere questo cancellando la proprietà Response.Filter in caso Application_Error:

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

chiedo se c'è un modo più corretto per farlo però ...

+0

Si potrebbe provare a creare una pagina di errore personalizzata? –

+0

Questo non risolve il problema. Devo essere in grado di vedere le informazioni sulle eccezioni, lo stack delle informazioni di tracciamento, ecc. Durante il debug. – Scott

+0

Ciò non significa che non puoi farlo usando l'attributo 'HandleError'. –

1

Ho avuto lo stesso problema in asp.net mvc 1.0 navigando per una pagina che aveva una RenderAction all'interno (dal gruppo dei futures). Apparentemente il problema era che la risposta veniva codificata due volte. Ho dovuto creare un filtro di azioni per queste azioni secondarie in modo che un flag sia impostato nella raccolta DataTokens di RouteData. Quindi ho dovuto modificare il filtro di compressione in modo che fosse restituito nel caso in cui il flag fosse impostato. Dovevo anche occuparmi dell'ordine di esecuzione dei filtri. Forse questo può aiutare, verificare se il filtro di compressione viene chiamato più di una volta quando viene sollevata una pagina di errore.

6

È inoltre possibile risolvere questo problema allegando a OnResultExecuting anziché OnActionExecuting. Ciò offre alcuni vantaggi

  1. È possibile scoprire il risultato dell'azione senza ricorrere alla riflessione.
  2. OnResultExecuting non verrà eseguito in casi eccezionali (MVC invocherà OnException ma non OnResultExecuting)

Qualcosa di simile a questo:

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

La risposta accettata non funzionerà se qualcosa è stato già scritto all'output.

Invece di smaltimento del filtro è possibile assicurarsi che le intestazioni siano persistenti sul posto:

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