Introduction
In this article I'm going to present the first version of my open source implementation of the fastcgi protocol under .NET framework. The purpose of this implementation is to have a more reliable solution than the one offered with Mono and also a more cleaner and reusable implementation of the protocol to host not only ASP.NET applications but also custom low level (and fast) applications, the ones that usually are implemented with an HttpListener. With this implementation is also possible to host an ASP.NET application (also MVC) with a Nginx webserver on both Windows and Linux.
About the fastcgi Mono implementation
You can find an implementation of the fastcgi protocol on Mono. If you'll have a chance to look at the source code, you will find that it's really overcomplicated. Also if you want to use it you will need to deploy the Mono libraries as long as it depends on them to work. The ultimate goal of the Mono implementation is to have a fastcgi replacement to host ASP.NET. My implementation includes this but also opens different implementation scenarios that are not possible under the mono implementation.
Background
To read this article you need to have a basic knowledge on how web servers and in particular IIS handles request. It would be also useful to have a basic understanding of webservices and how they are implement in .NET with the current available frameworks like for example WCF or ServiceStack.
Advantages
Your choice of web server
The main advantage of using this library is that you can use your choice of web server for your ASP.NET application instead of IIS. Nowadays, most of the web application that are traffic intensive (facebook, linkedin, etc) are now switching to implementations where the server is not thread based but works with asynchronous I/O (it's called IOCP under windows). For example both nginx and nodejs (libuv) use this pattern. In fact this pattern is more efficient when dealing with lots of concurrent requests because the CPU is not busy switching between threads but just runs a single thread (loop) where all the requests are handled.
So we can use a cool web server like nginx for our application but we are still tied to the thread model of ASP.NET! Unfortunately my fastcgi implementation can't solve itself this problem. But it's a first step towards a more efficient resources management.
You choice of C# web framework
The second advantage that the implementation of this library introduces is that you can decide not to use the standard ASP.NET stack but use your choice of web framework or better create your own! ASP.NET is designed around WebForms and introduces a lot of things like session management that are not always so efficient or cleanly implemented (for example have a look at this behaviour when dealing with concurrent requests using a read/write session here). The MVC framework it's amazing and solves a lot of the weirdnesses implemented to make the stateful WebForms model work. Anyway it's still based on the ASP.NET stack and still suffers a few of that. This is of course my opinion: there a are a lot of people out there that find the WebForms model great and use it with great success. Anyway, if you feel frustrated by it like me, you are not alone!
The fastcgi protocol
The fastcgi protocol works in a really simple way:
- the web server receives the request
note: if the request is a SSL(https) request it's also decrypted - the request is handled directly if it is for example a static resource
- if the request is for a dynamic page/resource, the request is forwarded to the fastcgi server
note: this usually requires configuration on the web server - the fastcgi server elaborates the response and sends it to the web server
- the web server writes back to the client (the user browser) the response
The fastcgi server is a TCP/IP server that listen for request forwarded by the web server. Most of the web server implements a single channel / request model. This means that for each request a new socket to the fastcgi server is created. Anyway the fastcgi protocol provide also a multiple request model for each channel (socket). The library currently support the first model but it's designed to easily implement the other model: the fact is that it's currently quite useless to implement it because of the lack of good web server side support.
All the data received and sent to the fastcgi web server are in memory (RAM): this is surely fast but it's totally inefficient when dealing with large requests/response. You will need to be very careful about this and consider other alternatives if planning to use a lot of large request/response.
Using the library
The easiest way to try/use the library is to run the nginx example included.
- Under Windows run nginx.exe included in the Examples folder or under Linux run nginx with the configuration supplied with the Windows example
- Start FastCgi.Test exe within visual studio or from a command prompt (in this case you will need to build it first)
- with a browser goto http://localhost:8080/info.aspx or http://localhost:8080/test.aspx
In the example, a simple ASP.NET website is used as a test. The Root folder contains these two pages where you can start having some experiments. In the Root\bin subfolder the DLLs for the website are copied: it includes as well the Fastcgi library.
When running the example a new application domain is created. This is required by the ASP.NET implementation, in order to isolate the web application. It's not possible to host an ASP.NET application without creating an application domain. I tried to be really simple on the implementation about this and I won't go into more details here as long as it's a quite complex topic. Anyway you can easily find a few articles that will cover it in more details here on CodeProject on msdn or on the web.
string path = Path.Combine(Directory.GetCurrentDirectory(), "Root");
SimpleServer server = (SimpleServer)ApplicationHost.CreateApplicationHost(typeof(SimpleServer), "/", path);
server.Start();
To make the ASP.NET stack handle the request the implementation creates a custom HttpWorkerRequest
called FastCgiWorkerRequest
, from the data received from the web server. This class also redirects the data elaborated by the ASP.NET application back to the web
server using the Request object from the fastcgi library. In other words this FastCgiWorkerRequest
is the link between the ASP.NET application and the fastcgi library.
Nginx configuration
To let the web server redirect the dynamic pages requests to the fastcgi server, I included this on the nginx configuration:
location ~ ^.+\.aspx {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index Default.aspx;
fastcgi_split_path_info ^((?U).+\.aspx)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
It simply redirects all the requests to a page that ends with .aspx to the fastcgi server.
If you can find on the web also other configurations working for MVC. In this case you won't be able to rely on the page extension. Instead you can
try the solution suggested on the nginx website.
Your opinion is important
I created this library as an exercise and to have some fun more than using it in a real world project. Anyway it's really simple, well designed, modular and commented.
I think you will find it really easy to customize/fork it
if you need to. I would be pleased to have suggestions of any kind like other kind of examples you would like to see or other web servers configuration examples.
In other words I would like to have some feedback.