Filtre de compression MVC 3 provoquant une sortie tronquée

J’ai donc un atsortingbut personnalisé appelé CompressAtsortingbute qui est configuré en tant que filtre global dans global.asax. Il utilise la reflection pour examiner le type de retour de la méthode d’action actuelle. S’il s’agit de “ViewResult”, il compresse la sortie à l’aide de GZip ou Deflate. Cela fonctionne très bien sauf si une page génère une erreur de 500 serveur. Si une erreur est rencontrée, au lieu d’afficher la page d’erreur .NET, je reçois un tas de ces informations:

`I % & / m {J J t

Apparemment, il tente de coder la page 500 Server Error qui cause des problèmes. Quelle est la meilleure façon de gérer cela?

Voici le code de filtre:

public override void OnActionExecuting(ActionExecutingContext filterContext) { MethodInfo actionMethodInfo = Common.GetActionMethodInfo(filterContext); if (GetReturnType(actionMethodInfo).ToLower() != "viewresult") return; HttpRequestBase request = filterContext.HttpContext.Request; ssortingng acceptEncoding = request.Headers["Accept-Encoding"]; if (ssortingng.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); } } 

    Ok, j’ai donc pu résoudre ce problème en effaçant la propriété Response.Filter dans l’événement Application_Error:

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

    Vous vous demandez s’il y a une façon plus correcte de le faire cependant …

    Vous pouvez également résoudre ce problème en attachant à OnResultExecuting au lieu de OnActionExecuting . Cela donne quelques avantages

    1. Vous pouvez découvrir le résultat de l’action sans recourir à la reflection.
    2. OnResultExecuting ne sera pas exécuté dans des cas exceptionnels (MVC appellera OnException mais pas OnResultExecuting )

    Quelque chose comme ça:

     public sealed class MyAtsortingbute : ActionFilterAtsortingbute { ///  /// Called by MVC just before the result (typically a view) is executing. ///  ///  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. } } 

    J’ai eu ce même problème dans asp.net mvc 1.0 en cherchant une page qui avait un RenderAction à l’intérieur (à partir de la future assembly). Apparemment, le problème était que la réponse était codée deux fois. Je devais créer un filtre d’action pour ces actions enfant afin qu’un indicateur soit défini dans la collection DataTokens de RouteData. Ensuite, j’ai dû modifier le filtre de compression afin qu’il soit renvoyé au cas où l’indicateur était défini. J’ai également eu à traiter l’ordre d’exécution des filtres. Peut-être que cela peut aider, vérifiez si le filtre de compression est appelé plus d’une fois lorsqu’une page d’erreur est générée.

    La réponse acceptée ne fonctionnera pas si quelque chose a déjà été écrit dans la sortie.

    Au lieu de jeter le filtre, vous pouvez vous assurer que les en-têtes sont maintenus en place:

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