C# 在ASP.NET MVC操作中同时使用Response.Filter和BufferOutput=true会导致ZLibException
我有一个ASP.NET MVC操作,它执行以下操作:C# 在ASP.NET MVC操作中同时使用Response.Filter和BufferOutput=true会导致ZLibException,c#,asp.net-mvc,iis,C#,Asp.net Mvc,Iis,我有一个ASP.NET MVC操作,它执行以下操作: public ActionResult Index() { /* assuming the client supports gzip since the error doesn't happen without it */ Response.Filter = new GZipStream(Response.Filter, CompressionMode.Compress); Response.AppendHeader(
public ActionResult Index()
{
/* assuming the client supports gzip since the error doesn't happen without it */
Response.Filter = new GZipStream(Response.Filter, CompressionMode.Compress);
Response.AppendHeader("Content-Encoding", "gzip");
Response.BufferOutput = false; // Removing this line allows it to succeed
return Content("Hello world");
}
它始终失败,但以下情况除外:
System.IO.Compression.ZLibException: The stream state of the underlying compression routine is inconsistent.
at System.IO.Compression.DeflaterZLib.Deflate(FlushCode flushCode)
at System.IO.Compression.DeflaterZLib.ReadDeflateOutput(Byte[] outputBuffer, FlushCode flushCode, Int32& bytesRead)
at System.IO.Compression.DeflaterZLib.System.IO.Compression.IDeflater.GetDeflateOutput(Byte[] outputBuffer)
at System.IO.Compression.DeflateStream.WriteDeflaterOutput(Boolean isAsync)
at System.IO.Compression.DeflateStream.Write(Byte[] array, Int32 offset, Int32 count)
at System.Web.HttpWriter.FilterIntegrated(Boolean finalFiltering, IIS7WorkerRequest wr)
at System.Web.HttpResponse.UpdateNativeResponse(Boolean sendHeaders)
at System.Web.HttpResponse.Flush(Boolean finalFlush, Boolean async)
at System.Web.HttpWriter.WriteFromStream(Byte[] data, Int32 offset, Int32 size)
at System.IO.Compression.DeflateStream.PurgeBuffers(Boolean disposing)
at System.IO.Compression.DeflateStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.IO.Compression.GZipStream.Dispose(Boolean disposing)
at System.IO.Stream.Close()
at System.Web.HttpWriter.FilterIntegrated(Boolean finalFiltering, IIS7WorkerRequest wr)
at System.Web.HttpResponse.FilterOutput()
at System.Web.HttpApplication.CallFilterExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step)
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
at System.Web.HttpApplication.PipelineStepManager.ResumeSteps(Exception error)
at System.Web.HttpApplication.BeginProcessRequestNotification(HttpContext context, AsyncCallback cb)
at System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context)
at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
at System.Web.Hosting.UnsafeIISMethods.MgdIndicateCompletion(IntPtr pHandler, RequestNotificationStatus& notificationStatus)
at System.Web.Hosting.PipelineRuntime.ProcessRequestNotificationHelper(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
at System.Web.Hosting.PipelineRuntime.ProcessRequestNotification(IntPtr rootedObjectsPointer, IntPtr nativeRequestContext, IntPtr moduleData, Int32 flags)
当从一个简单的IHttpRequest处理程序运行它时,我会得到同样的异常
删除BufferOutput=false
行可以让它毫无问题地运行,但是我希望能够添加压缩,不管响应是否被缓冲。我也无法修改web.config以全局打开压缩
似乎IIS在GZipStream正在写入的底层HttpResponseStreamFilterLink上设置了Filtering=true
,这是在请求完成后但在调用Close()
之前。
然后,当它调用Close()
时,GZipStream将其最后的几个字节写入底层流,IIS将这些字节传递回其输入,认为它们尚未被过滤。可以理解,GZipStream在关闭后拒绝写入并抛出异常
可以按如下方式包装GZipStream,以便在流关闭时绕过它:
class GZipHelper : Stream
{
public GZipStream GZip { get; }
private bool _closing;
public GZipHelper(Stream baseStream)
{
GZip = new GZipStream(baseStream, CompressionMode.Compress);
}
/* unimplemented Stream methods elided */
public override void Flush()
{
GZip.Flush();
}
public override void Write(byte[] buffer, int offset, int count)
{
if (!_closing)
{
GZip.Write(buffer, offset, count);
}
else
{
GZip.BaseStream.Write(buffer, offset, count);
}
}
public override void Close()
{
if (!_closing)
{
_closing = true;
base.Close();
GZip.Close(); // will call Write()
}
}
}
这将修复异常并生成正确的输出。然而,我不知道为什么这种变通方法是必要的
发生了什么事