Gzip / deflate failure on exception failure

I have an interesting problem with gzip / deflate ActionFilterAttribute in ASP.NET MVC 3. If an exception is thrown by my application, instead of getting YSOD, I get a full gibberish page, as shown below.

I %&/m {J J t $@ # Ig) * EVA] F @ 흼 {{; N "? \ FdlJɞ ~ | !?" Eu) = y6hZ2kjuU? + _x-: TWV <? [~ 2g2 ʋyhY Ջ t _N M l {, Xn Q} * g 7 ~ j'u>K {_ IW4 > U w |=-fYzR- | <& o Z()* S!U k g j . b} ή 9X/ J Iն Q z i n -g٤ ݞ Y^ H 8/ k }]7 ǜ@ {| g wUd O 죫y o- ݏ ZHv, d] ١ >o3 = 3x 7MN Ow w .o φ <؟M ; vg A> 䋟{YޟN Φ $p>q / ! y 9 2 two ? Ӈ n 9 r ^ ! { ag ?\1*c ?! bي ? xIuf? {'P $ v &! = # Sl_0΃wss 廌 ⼽ r {k \ 7M (o4 ߛ → @ "|| vy5Q ꆦ RJSK & ߛ ru <Ct1hOIy {J] I D'p <$ , 'M r{- } CF ؛ A 9 [ ½ ! 2 : ! { t ; ߇'y M + M^#x^\ Q jM l ?( ] IZ ݟ[ +4#" : X m dv> iL ̀I | fL TU ho {L _t 5 o? h O UY]# u [ G ޞ = ; 8 ~ d 8k w yw ֺ NXa [XMO F / Og ;! Y ~

If I remove my CompressAttribute , it works as expected (I see YSOD). So it seems that my exception handling ( ElmahHandleErrorAttribute from Elmah.Contrib.Mvc) stops the remaining filters, including CompressAttribute , and the response is not deflated.

Relevant Code:

 public sealed class CompressAttribute : ActionFilterAttribute { private const string _acceptEncodingHeader = "Accept-Encoding"; private const string _contentEncodingHeader = "Content-Encoding"; public override void OnActionExecuting(ActionExecutingContext filterContext) { HttpRequestBase request = filterContext.HttpContext.Request; string acceptEncoding = request.Headers[_acceptEncodingHeader]; if (String.IsNullOrEmpty(acceptEncoding)) { return; } acceptEncoding = acceptEncoding.ToUpperInvariant(); HttpResponseBase response = filterContext.HttpContext.Response; if (acceptEncoding.Contains("GZIP")) { response.AppendHeader(_contentEncodingHeader, "gzip"); response.Filter = new GZipStream(response.Filter, CompressionMode.Compress); } else if (acceptEncoding.Contains("DEFLATE")) { response.AppendHeader(_contentEncodingHeader, "deflate"); response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress); } } } 

Filter Registration:

 GlobalFilterCollection filters = GlobalFilters.Filters; filters.Add(new ElmahHandleErrorAttribute(), 999); // Elmah.Contrib.Mvc filters.Add(new CompressAttribute()); 

How can I make sure the answer is readable even if exceptions are thrown?

+4
source share
3 answers

This is because if an error occurs in your application, ASP.Net deletes all your own headers, but the filter still exists. You can reset the filter when an application fails, which should fix the problem.

 protected void Application_Error(object sender, EventArgs e) { Response.Filter = null; } 
+6
source

Here is a slightly better answer, inspired by the answer from iaimtomisbehave. It allows you to store all the code inside one class.

Add the following override to the CompressAttribute class:

 public override void OnResultExecuted(ResultExecutedContext filterContext) { if (filterContext.Exception != null) { filterContext.HttpContext.Response.Filter = null; } } 
+8
source

Turning on the Internet to solve the same problem ended here. Very helpful answers inspired me to implement my own version, mentioned below:

 static public void EnableGzip() { var c = HttpContext.Current; string a = c.Request.Headers["Accept-Encoding"]; if (String.IsNullOrEmpty(a)) return; if (!a.Contains("gzip")) return; c.Response.Filter = new GZipStream( c.Response.Filter, CompressionMode.Compress); c.Response.AppendHeader("Content-Encoding", "gzip"); EventHandler errorHandler = null; errorHandler = delegate { c.Response.Filter = null; c.ApplicationInstance.Error -= errorHandler; }; c.ApplicationInstance.Error += errorHandler; } 

Please feel free to criticize this.

0
source

Source: https://habr.com/ru/post/1396473/


All Articles