C# 在ASP.NET MVC操作中同时使用Response.Filter和BufferOutput=true会导致ZLibException

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(

我有一个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("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()
        }
    }
}
这将修复异常并生成正确的输出。然而,我不知道为什么这种变通方法是必要的

发生了什么事