如何使用HttpModule记录请求输入流,并重置输入流位置

33

我正在尝试使用类似于IHttpModule的东西记录http请求的内容,如下所示:

public class LoggingModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.BeginRequest += ContextBeginRequest;
    }

    private void ContextBeginRequest(object sender, EventArgs e)
    {
        var request = ((HttpApplication)sender).Request;
        string content;

        using (var reader = new StreamReader(request.InputStream))
        {
            content = reader.ReadToEnd();
        }

        LogRequest(content)
    }
}
问题在于读取输入流到末尾后,InputStream 似乎要么消失了,要么更可能的是光标位于流的末尾。
我已经尝试过 request.InputStream.Position = 0;request.InputStream.Seek(0, SeekOrigin.Begin);,但两者都不起作用。
6个回答

47

我解决了这个问题:我认为在 StreamReader 上调用 dispose 方法可能会导致 InputStream 被关闭。

我改变了做法,不再使用 StreamReader,而是采用以下方法:

        var bytes = new byte[request.InputStream.Length];
        request.InputStream.Read(bytes, 0, bytes.Length);
        request.InputStream.Position = 0;
        string content = Encoding.ASCII.GetString(bytes);

所以完整的代码:

public class LoggingModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.BeginRequest += ContextBeginRequest;
    }

    private void ContextBeginRequest(object sender, EventArgs e)
    {
        var request = ((HttpApplication)sender).Request;

        var bytes = new byte[request.InputStream.Length];
        request.InputStream.Read(bytes, 0, bytes.Length);
        request.InputStream.Position = 0;
        string content = Encoding.ASCII.GetString(bytes);

        LogRequest(content)
    }
}

7
请注意编码方式,我认为你需要使用 Encoding.UTF8.GetString(bytes) 来解码。 - SimonF
我在找出我的代码问题之前浪费了一整天的时间。非常感谢你! - programmer22222

23

是的,StreamReader将关闭提供的流。

如果您使用的版本是大于v4.5,则请使用保留流打开的StreamReader构造函数。

using (var reader = new StreamReader(request.InputStream, Encoding.UTF8, true, 1024, true))
{
    content = reader.ReadToEnd();
}

3

我对“cbp”提供的答案进行了微调。在使用他的代码时,我只得到了零。我将设置位置为0的操作移到读取之前,现在它可以正常工作。

 var bytes = new byte[Request.InputStream.Length];
 Request.InputStream.Position = 0;
 Request.InputStream.Read(bytes, 0, bytes.Length);
 string content = Encoding.ASCII.GetString(bytes);

2

这个答案不起作用。它返回一个包含 null 值的数组。

 var bytes = new byte[request.InputStream.Length];
 request.InputStream.Read(bytes, 0, bytes.Length);
 request.InputStream.Position = 0;
 string content = Encoding.ASCII.GetString(bytes);

因为输入流被消耗掉了。


1
你需要使用一个请求过滤器。编写一个继承自Stream的类,并将其注册为过滤器。

请详细说明这种方法与其他答案相比的优越性?它不需要重置流吗? - Maulik Modi

-1
有时候,RequestFilter 不会运行到 Read 方法。看起来 W3WP 没有以正常方式读取 httprequest 的内容。
如果您将 WEbservice 部署到服务器上,请使用 IHttpModule 进行捕获。添加 RequestFilter
但是,RequestFilter 的 Read() 方法不会运行 :P

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接