2013-11-27 54 views
8

我想扩展我的REST服务(使用WCF/webHttpBinding构建),以便客户端可以上传经过压缩的数据。我不确定要达到这个目的的最佳方式,但是我认为通过添加一个HTTP模块可以相当容易,该模块将在传入请求的Content-Encoding设置为gzip时解压缩数据。我可以使用HTTP模块更改传入HTTP请求的内容吗?

所以我创建了一个类从IHttpModule的导出具有以下实现:

private void OnBeginRequest(object sender, EventArgs e) 
    { 
    var app = (HttpApplication) sender; 
    var context = app.Context; 

    var contentEncoding = context.Request.Headers["Content-Encoding"]; 

    if (contentEncoding == "gzip") 
    { 
     // some debug code: 
     var decompressedStream = new GZipStream(context.Request.InputStream, CompressionMode.Decompress); 
     var memoryStream = new MemoryStream(); 
     decompressedStream.CopyTo(memoryStream); 
     memoryStream.Seek(0, SeekOrigin.Begin); 

     var streamReader = new StreamReader(memoryStream); 
     string msg = streamReader.ReadToEnd(); 

     context.Request.InputStream.Seek(0, SeekOrigin.Begin); 

     app.Request.Filter = //new TestFilterStream(app.Request.Filter); 
        new System.IO.Compression.GZipStream(
        app.Request.Filter, CompressionMode.Decompress); 
    } 

    } 

我看到的问题是,从来没有实际执行GZipStream减压。我已经确认传入的数据实际上是gzip'd(msg变量包含正确的数据)。我也尝试创建我自己的流类(TestFilterStream),并将其分配给app.Request.Filter,并且我确认了流类中没有成员实际上由ASP.NET调用。所以看起来好像虽然可以指定一个过滤器,但实际上并未使用该过滤器。

是不是实际使用了HttpApplication.Request.Filter?

+0

你有没有尝试过设置'Request.Filter'没有你的其他调试代码?这可能是因为您已经阅读了请求流,因此它不会再应用此过滤器。 –

+0

我相信没有理由相信Request.InputStream是可搜索的。它可能不是。尝试删除你的调试代码,它可能是错误的(你可能必须关闭/冲洗decompressedStream才能真正写入内存流)。 – Luaan

+1

请缩小这个问题的范围,因为从您的问题中不清楚实际发生的错误以及何时发生。问题实际上'GZipStream'没有读取底层流? 'contentEncoding'等于''gzip“','if'块中的代码被调用了吗?您是否尝试过记录此方法被调用的时刻?你甚至确定你的模块被加载了吗? – CodeCaster

回答

0

我刚刚完成了一些测试,并且只要有请求主体和请求主体被http处理程序读取,我的Request.Filter流就会被调用。我猜你使用PUT或POST,并肯定读取请求正文,所以这应该不成问题。

我怀疑Knaģis的评论是正确的。您是否尝试过没有调试代码?如果我深入研究HttpRequest源代码,我会看到一个变量_rawContent正好写入一次;同时应用请求过滤器。之后,_rawContent值只被缓存,并且从不更新(在添加过滤器时也不会重置)。

因此,通过在调试代码中调用Request.InputStream,您肯定会阻止稍后应用您的过滤器。读取Request.Headers集合是没有问题的。

2

我尝试设置请求过滤在两个方面:

  1. 使用的HttpModule
  2. Application_BeginRequest()开始设置它(Global.asax中)

两者具有相同的结果( VS2012 web项目+ IISExpress):

  • 如果没有输入数据(GET请求或类似的),t他Filter.Read不会被调用
  • 与实际数据的POST的情况下,执行过滤器和Web服务得到过滤后的数据
  • 即使我从Request.InputStream读取设置过滤器前,我仍然得到过滤器从我的服务代码触发。

我没有简单的方法用Gzippet输入进行测试,所以我没有尝试过,如果实际的过滤器工作。但是,我知道它正在被触发,因为我在尝试查找输入时从GZipStream得到一个错误。

也许你有其他的HttpModules或过滤器会破坏你的输入或控制流?

This post提出类似你一个方法,而且还规定了以下内容,这可能会导致一些副作用(我的测试中没有使用WCF):

“看来,这种做法引发的问题WCF,因为WCF依赖于原始的Content-Length而不是解压后获得的值。“

0

你确定,应用程序本身应该打扰吗? 通常这是根据主机(IIS)的配置处理的。所以,基本上,当你自己托管服务时,你只需要实现自定义的GZip支持。 你可以看看here

相关问题