C# HTTP响应过滤器可以';t第二次解码响应字节

C# HTTP响应过滤器可以';t第二次解码响应字节,c#,iis-7.5,httpresponse,httpmodule,C#,Iis 7.5,Httpresponse,Httpmodule,我开发了一个iis7httpmodule。我的目标是检查特定标记的响应内容。如果找到标记,则会记录一些内容 为了实现我的目标,我开发了一个定制的ASP网络响应过滤器。此筛选器扩展.NET流类 在OnPreRequestHandlerExecute(对象源,EventArgs e)事件上注册筛选器 HTTP模块已正确注册。过滤器正在工作。问题是,当我刷新页面时,Write-The-Write(byte[]buffer,int-offset,int-count)方法按预期被调用,然而,在解码字节时,

我开发了一个iis7httpmodule。我的目标是检查特定标记的响应内容。如果找到标记,则会记录一些内容

为了实现我的目标,我开发了一个定制的ASP网络响应过滤器。此筛选器扩展.NET流类

在OnPreRequestHandlerExecute(对象源,EventArgs e)事件上注册筛选器

HTTP模块已正确注册。过滤器正在工作。问题是,当我刷新页面时,Write-The-Write(byte[]buffer,int-offset,int-count)方法按预期被调用,然而,在解码字节时,字节的内容是gobbledygook

这让我感到困惑,为什么第一次响应字节被正确解码,但是在第二次请求(即页面刷新)之后它们却没有被正确解码。下面是设置过滤器的编码位置以及过滤器的writer方法的代码。任何帮助都将不胜感激,因为我已经花了3天时间在谷歌上调试、研究,但仍然没有任何乐趣

public void OnPreRequestHandlerExecute(Object source, EventArgs e)
{

    HttpResponse response = HttpContext.Current.Response;
    if (response.ContentType == "text/html")
    {
        response.ContentEncoding = Encoding.UTF8; //forcing encoding UTF8
        response.Charset = "charset=utf-8";
        Encoding encoding = response.ContentEncoding;
        string encodingName = encoding.EncodingName;
        response.Filter = new MyFilter(response.Filter, response.ContentEncoding);
    }
}

    public override void Write(byte[] buffer, int offset, int count)
    {
        string strBuffer = string.Empty;

        try
        {
            strBuffer = Encoding.UTF8.GetString(buffer);
        }
        catch (EncoderFallbackException ex)
        {
            log(ex.Message);
        }


        // buffer doesn't contain the HTML end tag so we keep storing the 
        //incoming chunck of data

        if (!strBuffer.Contains("</html>"))
        {
            log(strBuffer.ToString() );
            _responseHtml.Append(strBuffer);

        }
        //the strbuffer contains the HTLM end tag ; we wrap it up now
  else
        {
            _responseHtml.Append(strBuffer); //append last chunck of data
            string finalHtml = _responseHtml.ToString();


               byte[] bytesBuffer = Encoding.UTF8.GetBytes(finalHtml);
                outputStream.Write(bytesBuffer, 0, bytesBuffer.Length);
            }

        }

    }
。。。。 ..…
}

ProcessResponseContent是一个哑方法。它只是将字节列表转换为字节数组;这个字节数组被解码成一个字符串。现在我们不应该有任何问题,因为我们得到了所有的字节,发送到响应中,在字节列表(列表)中

字节数组将原封不动地返回,因为代码的目的是将解码的字符串登录到文件中

        log("after decoding  " + html);
在创建UTF8编码时,我捕获到一个异常。将异常记录到一个文件中

第一次检索html页面时,内容会记录到文件中

当我刷新页面(Ctrl+F5)时,会记录一个异常:

“出现异常无法将索引0处的字节[8B]从指定代码页转换为Unicode”

请记住,我的html页面内容非常小。在一个块上处理所有响应内容

第一次访问页面时,收到的字节数为2805。就在这些字节被解码成字符串之前

第二次调用页面时(Ctrl+F5),在解码之前接收到的字节数为1436

为什么响应的字节数较少,我不确定。 这可能会影响解码操作

我希望这一切都有意义,请让我知道,如果有什么不清楚。我已经研究这个代码很长时间了


谢谢,

很难判断这是否是问题的全部,但是您忽略了
写入中的
偏移量
计数
参数,而是假设整个缓冲区都有效:

strBuffer = Encoding.UTF8.GetString(buffer);
您还假设这将是一组完整的字符-它可能只包含(比如)三字节字符中的两个字节。您需要使用从
Encoding.UTF8
创建的
Encoder
使流有状态,以保持调用之间部分写入字符的状态


还请注意,您假设在一次调用中可以得到全部
,而在下一次调用中可以得到
。有可能ASP.NET实际上只在最后给您打了一次电话,但您可能不应该假设是这样。

谢谢您的回复Jon。流是过滤器类私有流outputStream的私有成员;调试期间我注意到的一件事是,页面刷新时会调用过滤器的构造函数;所以我想知道构造函数是否是创建流对象实例的最佳位置。你给了我一些很好的观察;我将实现一些更改,并让您知道它是如何进行的。我的意思是,在提供的代码中使用的流是filter类的私有成员。这就是你所说的“有状态”吗?@Marlon:我的意思是你需要更多的状态,以编码器的形式来处理部分字符。
       byte[] bytesArray = bytesList.ToArray();
        string html = string.Empty;
        byte[] encodedBytes = null;

        try
        {
            FilterEncoder encoder = new FilterEncoder();
            html = encoder.DecodeBytes(bytesArray.Length, bytesArray);
            encodedBytes = encoder.EncodeString(html);
            log("after encoding - encodedBytes" + encodedBytes.Length);
            log("after encoding - bytesArray" + bytesArray.Length);
        }
        catch (Exception ex)
        {
            log("exception ocurred " + ex.Message);
        log("after decoding  " + html);
strBuffer = Encoding.UTF8.GetString(buffer);