IIS7 was revolutionary in opening the IIS web server platform for public extensibility. Prior to that, few software vendors wrote extensions for IIS, using the native ISAPI Filter and Extension APIs. IIS7 completely changed this, creating a public extensibility model on top of which the web server itself was implemented, and opening it for managed development via the familiar ASP.NET API.
Here are a couple things you can do only with native modules, and why you will probably never have to do them.
In the dark ages, there was ISAPI
Before IIS7, the only way to extend IIS was the C++ ISAPI Filter or Extension API. This was as complicated and error prone as any native server development, and also had limited ability to extend IIS. Most of the IIS features themselves were hardcoded into the monolithic IIS core, and ISAPI made it possible to implement some very specific scenarios to “work around” the built-in request processing. Only a few software vendors dared to build ISAPI components, and the rest of the world was forced to buy them to be able to customize IIS.
IIS 7 brought extensibility into the public domain
IIS7 changed this completely, by creating a public extensibility API and literally building itself on top of it. This way, we made sure that anyone could extend IIS to do everything we could do, because we would both build on the same API. As a result, the webserver became a small request processing pipeline with 40+ optional modules that implemented all the features, such as authentication, compression, caching, static file serving, URL rewriting, and so on.
More importantly, IIS7 delivered the Integrated Pipeline, the engine that enabled ASP.NET developers to extend IIS with the ASP.NET IHttpModule and IHttpHandler APIs. This was huge, because it effectively eliminated the need for native C++ development in order to extend IIS.
To make this happen, we had to fit the existing ASP.NET API over the new IIS7 model, without breaking backward compatibility with ASP.NET, and allowing the ASP.NET APIs to have as much power to extend IIS as possible. Also while meeting the performance requirements of the NT PERF team, that were historically based on much faster native-only IIS benchmarks. It was an insanely complicated technological feat, which I’ll talk about in another post.
So, is there anything I cant do with managed modules?
There are still a couple things that you have to write a native module for.
1. Run in PRE_BEGIN_REQUEST.
This is a special event that occurrs at the very beginning of the request, before IIS has mapped the URL to a physical location, and before it has loaded configuration. A few select native modules use this event for very rapid processing, e.g. the IIS Request Filtering module uses it to rapidly reject danerous requests.
2. Use module priorities.
IIS allows modules to register for request notifications using a priority level, which can range between LAST, LOW, MEDIUM, HIGH, and FIRST. ASP.NET modules are always registered as MEDIUM, meaning that any native module can always elect to run before regardless of their configuration order.
3. Send response asynchronously.
In my opinion, this is one of the most significant limitations. ASP.NET by default buffers the response in memory, and only provides a synchronous HttpResponse.Flush() method for flushing it to the client. If you wanted to efficiently spool large responses to hundreds of concurrent users, you’d have to write a native module that uses asynchronous response writes.
Correction: you can flush ASP.NET response asynchronously with ASP.NET 4.5! Very happy this finally happened, just like the new ability to asynchronously preload request entity. Interestingly enough, both of these features were assigned to me back in 2007, but we just ran out of time to build them (and I regretted that ever since).
4. Intercept/filter request POST data.
While ASP.NET modules can filter the incoming request entity body via the HttpRequest.Filter stream, its not a true filtering mechanism because it requires preloading the entire request into memory/disk first. Secondly, that data will be loaded by ASP.NET, and cannot be made available to a non-ASP.NET application (like PHP or classic ASP). You would have to write a native module to efficiently filter the request data on the fly, preload the request entity asynchronously, and make it available to non-ASP.NET clients.
5. Handle global notifications: MapPath, ConfigurationChange, HealthCheck, RSCAQuery, etc
IIS has global notifications that allow native modules to override functionality for mapping URLs to files, handling async configuration changes, responding to external status requests via the Runtime Status and Control API, and more. These are not available to ASP.NET modules.
6. Get precise control over performance and resource use.
When people ask me whether they should write a native module, my answer will always be – never! It just takes too long to build, stabilize, and support native code – and its next to impossible to find developers these days who can maintain it well.
Now, dont get me wrong. There are few things I enjoy more than writing C++ code, and carefully moving bits with precise control over memory, IO, and the win32 API. I’ve personally written quite a few of these very complex, very performance centric native modules, including the IIS7 Bit Rate Throttling module, and LeanServer ScaleUP, the absolutely fastest way to do HTTP uploads to an IIS server. But, as much as I enjoy this, I would never consider writing a native module if its possible to write a managed one, for the same reason that its been years since I’ve written anything in C++.
Nowadays, you can do almost anything with .NET, using the comprehensive support of the .NET framework and plugging any holes with p/invoke to win32 APIs or COM interop. You can even run .NET on Server Core (which you couldnt do for all of 5 minutes when Windows Server 2008 first came out).
Consider this short but sweet list of reasons why you should only build ASP.NET modules:
- They take 10 times less time build, and cost 100 times less to support.
- You can find sample code on how to do anything you ever needed.
- Any .NET developer can write ASP.NET modules, but I wouldnt let most developers near C++ server code.
- ASP.NET modules automatically deploy with your application.
- ASP.NET modules can run in shared hosting environments, including Microsoft Azure Websites, where native modules don’t (they require Administrative priviledges to install).
This is exactly why the ASP.NET Integrated Pipeline was such a huge win for the Microsoft web platform. It removed native development as a requirement for extending the web server, and made it an option for those few that really need it.
So, next time you find yourself tearing your hair out because of an old unsupported ISAPI filter in your application, consider sitting down for a couple hours and rewriting it to an ASP.NET module. It will be faster, cheaper, and you wont have to pay anyone or make international phone calls next time it breaks.
Andrew
“Things you still cant do..” – use apostrophes?
Thorn
In other words, M$ as usual made a toy with ugly architecture and hardcoded “goodies”.
Reading all that limitations I don”t see what MS improved at all.
When MS will hire normal developers? Their hindu code suxx.
Devmano
Thanks a lot for this great Article, it really shed some important light on a question that has been hunting me for long time.
if you don”t mind I have question, regarding streaming, is it wise to write an ASP.Net HTTP Module or native module to handle that with same performance ?
currently only options to have streaming on Windows that support all devices is either WOWZA Media Server
http://www.wowza.com/
or Unified Streaming Platform
http://www.unified-streaming.com/
which uses IIS Native Module.
Mike
@Andrew, thanks! Corrected.
Mike
@Thorn. I think you completely missed the point 🙂 After IIS7 you can virtually do anything on IIS7 via the ASP.NET API, and the entire server is built on the open extensibility model with almost nothing hardcoded into the core.
Mike
@Devmano,
With ASP.NET 4.5, its finally possible to stream to a client. I would consider this route first, before you think about writing a native module to do it.
You would need to stream asynchronously (think about those slow mobile clients), and be careful about the amount of buffering you are doing, to achieve good scale.
An alternative approach is if you already have the file on disk, you are almost always better using the HttpResponse.TransmitFile API, which causes IIS to asynchronously spool the file to the client after the request has finished.
Best,
Mike
Devmano
thanks a lot Mike for the Answer, so in other words, with 4.5 i can eliminate the need for the 2 libraries i have mentioned ?
Azadeh
hi
i write a dll in project ATL with a function witch function inclusive a input and output parameter is that byte* type
STDMETHODIMP CMSDllServer::sum22(BYTE* aa,SHORT len)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
for(int i=1;i<len;i++)
{
aa[i]=i;
}
return S_OK;
}
in use during from this function in a windowes application c# doesnot exist no problem and array values returned to truth
byte[] Packet = new byte[5];
dllServer.sum22(ref Packet[0],5);
//out put
1,2,3,4,5
but
the same function in a webservice returned to only first index array and exist very big problem
byte[] Packet = new byte[5];
dllServer.sum22(ref Packet[0],5);
//out put
1,0,0,0,0
help me pleaseeeeeeeeeeeeeeeeeeeeeeeeeeeee
thanx
Furkan YILDIRIM
So we can do asynchronous response writes, I gotta try it immediately ! goodbye testing postbacks 🙂
Mohammad Bilal
thnx. Dear can you give me suggestion or code to find back links to my or any website in asp.net(C#).
feee3.com
Great site. Plenty of useful information here. I’m sending it to several friends ans also sharing in delicious. And obviously, thank you in your effort!
Daniel Spång
@Mike Using native modules, is it possible to extract the _raw_ http request, as a string, not just the one parsed into HTTP_REQUEST structure that can be acquired from IHttpRequest::GetRawHttpRequest()?
See http://stackoverflow.com/questions/1038466/logging-raw-http-request-response-in-asp-net-mvc-iis7 for some context.
Rick Sprenkle
I’ve found a weird limitation of IIS 7, that isn’t a problem with my iisexpress test environment…
If I offload some of my work inside a managed handler using a C++/CLI library call, all is fine. But if that C++/CLI dll references a native dll call for a single method, all handlers are disabled, with an error call “Unable to load assembly”.
Looking at the tempInternet files (under the windows .NET framework), I can see that it looks like it fails mid copy from the sitebin folder to the .NET temporary folder — my guess is that it doesn’t know to bring along the dependency dll..
Any thoughts on how to get around this (without rearchitecting our extensive libraries)
Scott
Native ISAPI is not C++. Native ISAPI DLL’s can be written in other languages as well. For example. It’s quite easy to develop an native ISAPI DLL in object pascal (Delphi). It’s stable, small and extremely fast. So my first choice would always be native ISAPI unless there is a good reason to do otherwise.
It is true that it takes some considerations about memory management and parallel code. But that’s knowledge every good programmer should have. If you do it well native ISAPI can make a difference between the need for one server versus five, for the same function.
pregunton
What’s about performance for
http://www.endurasoft.com/blog/post/implementing-an-asynchronous-httpmodule.aspx
ASP.NET Async SessionState module
https://www.nuget.org/packages/Microsoft.AspNet.SessionState.SessionStateModule/
https://www.nuget.org/packages/Microsoft.AspNet.SessionState.SqlSessionStateProviderAsync/
are good performance ?