Patrick Farrell
Patrick Farrell

Reputation: 483

Operate on HTTP Request as it is received in IIS in C#

I have a need to override the receipt of a raw HTTP request as it is being communicated to an IIS server. I want to know if this is possible.

We have a client who sends huge Web Service calls (tens of Mb) and we want to start acting on portions of those calls as they are being received (in order to get a faster total time of execution for the Web Service call).

Currently, using normal web service methods, our application code is handed the Web Service call after it is totally received.

I realize this isn't the ideal way of handling Web Services, and we're not building our business on this, but we do have an need that we're trying to fill for a limited range of customers.

I have created a handler that implements IHttpHandler, but it appears that at this point in the process pipeline, the Request has been fully received by IIS (which doesn't get us any benefit over our current model). That is, I can read the InputStream directly, but the full request has already been transferred over the wire before I have access to this stream.

I think the answer is that I have to code an ISAPI filter to get this far down, but I don't have the skills to do this in C/C++. Does anyone know if there's another way I can do this without the ISAPI filter route?

An acceptable answer could be, "You have to do this as and ISAPI filter, to do it in C#, check this doc".

Upvotes: 1

Views: 1939

Answers (3)

Ian Boyd
Ian Boyd

Reputation: 257047

Short Version

The solution is to use HttpRequest.GetBufferlessInputStream.

Long Version

The issue is that if you attempt to use:

you must wait until the whole request has been received before it returns a Stream object. In contrast, the GetBufferlessInputStream method returns the Stream object immediately. You can use the method to begin processing the entity body before the complete contents of the body have been received.

This method can be useful if the request is uploading a large file and you want to begin accessing the file contents before the upload is finished. However, you should only use this method for scenarios where you want to take over all processing of the entity body. This means that you cannot use this method from an .aspx page, because by the time an .aspx page runs, the entity body has already been read.

The only downside, and it is a huge downside, is that you are now reading the Request.InputStream. This means you have to handle the MIME multiparts, and the base64 encoding, yourself.

Example (untested) code

UploadFile.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;}
}

Bonus Reading

Upvotes: 0

Jeff Hardy
Jeff Hardy

Reputation: 7662

You can use a custom HttpModule to hook almost any part of the IIS pipeline. They work in both IIS 6 (under ASP.NET) and are the primary extension mechanism in IIS 7.

Upvotes: 1

cmdematos.com
cmdematos.com

Reputation: 1994

There are plenty of examples of building ISAPI filters, but none in C#. I am sure it is possible, but not practical and not without lots dirty tricks.

Your C# investment will hold up well in C++, let me know if you need help. By the way, I recommend you invest in the my standard trio - try to keep up a healthy knowledge of C#, C++ and Java.

I also recommend you consider Apache modules, they may offer more overall flexibility. This is what I would do:

  1. host these web services off of IIS - you never know when IIS will bite you by resetting the application.
  2. Use WCF services, host these from Windows services, use redirection to route the service to the WCF service.
  3. Consider writting a raw sockets application. This one would implement the minimal WS:* protocol to your service and act as a proxy for the real service. When the proxy detects that the inbound message is exceeding a threshold it would begin analyzing the message to extract out what it could process right away.

The result would be standard WCF (through proxy) for smaller messages and non-standard processing for everything else.

Let me know if I can help you build it - this is the kind of thing I like to do...

Oh - and I recall now that WCF is completely configurable. You will be able to provide your own handlers for a variaty of layers and resolve everything from within managed code after all.

Upvotes: 0

Related Questions