I have an interesting issue with a gzip/deflate ActionFilterAttribute in ASP.NET MVC 3. If an exception is thrown by my application, instead of getting a YSOD, I get a full page of gibberish as seen below.
���
I�%&/m�{J�J��t��
$ؐ@�������iG#)�*��eVe]f@�흼��{����{����;�N'���?\fdl��J�ɞ!���?~|?"��Ey�')=��y6�����h����Z��2k�j���uU?�+_x-��:� �T����W�v�<[����~2�g�2���?�ʋ�y�hYՋ�������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ي
?���xI����u�f ?��{'�����P$�v&=#s�l�_0�����w�ss�����廌��⼽�r���!��{k\7M���(o������4�ߛ>�>�@"|�|v���y5�����QꆦR���JSK�&�����ߛ�p������v<�C��t��1�hOI���y{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�
����ֺ��Nx��A���[��xMo��ۣf���/�Og�;y~����!
If I remove my CompressAttribute
, it works as expected (I see the YSOD). So it seems that my exception handling (ElmahHandleErrorAttribute
from Elmah.Contrib.Mvc) halts 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 that the response is readable even when exceptions are thrown?
Here is a slightly better answer inspired by the answer from iaimtomisbehave. It lets you keep all of the code within the one class.
Add the following override to your CompressAttribute class:
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.Exception != null)
{
filterContext.HttpContext.Response.Filter = null;
}
}
This is because when there is an error in your application ASP.Net removes all your custom headers but the filter is still there. You could reset the filter on application error that should make the problem go away.
protected void Application_Error(object sender, EventArgs e)
{
Response.Filter = null;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With