【问题标题】:Operate on HTTP Request as it is received in IIS in C#在 C# 的 IIS 中接收到 HTTP 请求时对其进行操作
【发布时间】:2009-08-08 03:11:01
【问题描述】:

我需要覆盖原始 HTTP 请求的接收,因为它正在与 IIS 服务器通信。我想知道这是否可能。

我们有一个发送大量 Web 服务调用(数十 Mb)的客户端,我们希望在收到这些调用时开始对部分调用采取行动(以便更快地执行 Web 服务调用的总时间)。

目前,使用普通的 Web 服务方法,我们的应用程序代码在完全接收到 Web 服务调用后被交给它。

我意识到这不是处理 Web 服务的理想方式,我们并没有在此基础上建立我们的业务,但我们确实有一个需要,我们正在努力满足有限范围的客户。

我创建了一个实现 IHttpHandler 的处理程序,但似乎在流程管道中的这一点上,请求已完全被 IIS 接收(与我们当前的模型相比,这并没有给我们带来任何好处)。也就是说,我可以直接读取 InputStream,但在我访问该流之前,完整的请求已经通过网络传输了。

我认为答案是我必须编写一个 ISAPI 过滤器才能实现这一目标,但我没有在 C/C++ 中执行此操作的技能。有谁知道是否有另一种方法可以在没有 ISAPI 过滤器路由的情况下做到这一点?

一个可接受的答案可能是,“您必须使用 ISAPI 过滤器执行此操作,要在 C# 中执行此操作,请查看此文档”。

【问题讨论】:

    标签: c# iis httpwebrequest


    【解决方案1】:

    您可以使用自定义 HttpModule 来挂钩 IIS 管道的几乎任何部分。它们适用于 IIS 6(在 ASP.NET 下),并且是 IIS 7 中的主要扩展机制。

    【讨论】:

    • 我在这里可能是错的,从未尝试过 - 但我认为 HttpModule 在这种情况下不会工作。这里的关键是在请求被完全接收之前开始处理请求。似乎在调用 HttpModule 时,IIS 已经读取了整个请求(尽管没有处理)。 “在读入时”处理大型请求的唯一方法是处理来自套接字的原始数据流 - 或尽可能接近。 ISAPI 过滤器似乎足够低,如果有人知道更好,请告诉我们。
    • cmdemanto,这是我尝试使用 HttpModule 的经验。感谢您的帮助,Jeff,但似乎 IIS 直到读取整个请求流之后才引发 BeginRequest 事件。至少,这是我能够确定的。如果你知道我错了,我真的很感激一些代码,因为我不知道该怎么做。
    • NeatUpload (brettle.com/neatupload) 似乎做了一些类似于你想做的事情。它是开源的,所以也许你可以检查一下? (当我看到你的问题时,我就是这么想的。)
    • 杰夫,这很酷。我会检查一下。这可能会奏效。我还发现你的答案是正确的。 IIS 7,当在集成管道模式下运行时,使 HttpModules 能够访问覆盖本机代码功能(也许)。我不运行 Vista,所以我现在无法测试,但我的代码可能会“神奇地”在我部署的情况下工作。我会把我的结果发回这里。非常感谢您提供的信息。
    【解决方案2】:

    有很多构建 ISAPI 过滤器的示例,但在 C# 中没有。我敢肯定这是可能的,但不实用,也不是没有很多肮脏的把戏。

    您的 C# 投资将在 C++ 中表现良好,如果您需要帮助,请告诉我。顺便说一句,我建议您投资我的标准三重奏 - 尝试保持对 C#、C++ 和 Java 的健康了解。

    我还建议您考虑使用 Apache 模块,它们可能会提供更多的整体灵活性。这就是我会做的:

    1. 在 IIS 之外托管这些 Web 服务 - 您永远不知道 IIS 何时会通过重置应用程序来咬您。
    2. 使用 WCF 服务,从 Windows 服务托管这些服务,使用重定向将服务路由到 WCF 服务。
    3. 考虑编写一个原始套接字应用程序。这将为您的服务实现最小的 WS:* 协议,并充当真实服务的代理。当代理检测到入站消息超过阈值时,它将开始分析消息以提取它可以立即处理的内容。

    结果将是针对较小消息的标准 WCF(通过代理)和针对其他所有内容的非标准处理。

    如果我可以帮助您构建它,请告诉我 - 这是我喜欢做的事情......

    哦 - 我现在记得 WCF 是完全可配置的。毕竟,您将能够为各种层提供自己的处理程序,并从托管代码中解决所有问题。

    【讨论】:

    • 感谢 cmdematos,我认为您是对的,这需要 ISAPI 过滤器。我不确定我们是否会继续推进这个项目,因为我们不是 C++ 商店,你的第三个建议可能是我们必须走的路。我将不得不等待上级打来电话(这是周一的交付成果;)
    【解决方案3】:

    短版

    解决方法是使用HttpRequest.GetBufferlessInputStream

    加长版

    问题是,如果您尝试使用:

    您必须等到收到整个请求后,才能返回 Stream 对象。相比之下,GetBufferlessInputStream 方法会立即返回 Stream 对象。您可以使用该方法在收到正文的完整内容之前开始处理实体正文。

    如果请求正在上传大文件并且您希望在上传完成之前开始访问文件内容,则此方法很有用。但是,您应该只在要接管实体主体的所有处理的情况下使用此方法。这意味着您不能在 .aspx 页面中使用此方法,因为在 .aspx 页面运行时,实体主体已被读取。

    唯一的缺点,也是一个巨大的缺点,是您现在正在阅读 Request.InputStream。这意味着您必须自己处理 MIME 多部分和 base64 编码。

    示例(未经测试)代码

    上传文件.ashx

    public class Default : IHttpHandler 
    {
       public void ProcessRequest (HttpContext context) 
       {
          var request = context.Request;
    
          var stm = request.GetBufferlessInputStream(true); //true --> disable web.config limits on request size
          if (!stm.CanRead) 
             throw new Exception("Request input stream is not readable");
    
          //Setup the buffer we'll be shuffling stream data into
          int bufferLength = 16 * 8040; //use a multiple of 8040 bytes, because SQL Server uses pages of 8040 bytes. And because i'm saving it into SQL Server.
          byte[] buffer = new Byte[bufferLength];
    
          int bytesRead;
          bytesRead = stm.Read(buffer, 0, buffer.Length);
          while (bytesRead > 0)
          {
             SavePiece(buffer, bytesRead); //whatever you want to do with it
             bytesRead = stm.Read(buffer, 0, buffer.Length);
          }
       }
    
       private void SavePiece(byte[] buffer, int bufferLength)
       {
          //It's all going to be multipart mime encoded nonsense.
          //Good luck!
       }
    
       public bool IsReusable { get { return false;}
    }
    

    阅读奖励

    【讨论】:

      猜你喜欢
      • 2020-10-19
      • 2010-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-30
      • 2017-11-11
      • 1970-01-01
      • 2017-04-30
      相关资源
      最近更新 更多