ASP.NET中你可以通过继承IHttpHandler这个接口来实现一个同步(Synchronous)处理用户请求的类。比如你希望对于一切类型为fakephp的请求都通过你的Http Hanlder来处理,你可以实现以下这个类:
using System;然后通过在IIS里将你的dll注册为.fakephp的handler就可以了。这些在以下的MSDN文档里都有介绍: http://msdn2.microsoft.com/en-us/library/system.web.ihttphandler.aspx
using System.Web;
public class FakePHPHttpHandler : IHttpHandler {
public void ProcessRequest(HttpContext context) {
//let's pretend we can handle PHP stuff
}
public bool IsReusable {
get { return true; }
}
}
这里想说的是如何实现一个异步(Asynchronous)d的HTTP Handler。说起来其实也简单,只要实现IHttpAsyncHandler这个接口就好了。
IHttpAsyncHandler有两个method:
BeginProcessRequest
Initiates an asynchronous call to the HTTP handler.
EndProcessRequest
Provides an asynchronous process End method when the process ends.
这显然是和.NET Framework中标准的Asynchronous Programming Model (或者叫“异步模式”, Asynchronous Pattern)是一致的:
参考: Asynchronous Programming Overview
异步模式的优势是ASP.NET的worker thread不会等待BeginProcessRequest返回而是会掉头去接收其他的用户请求(当然你也可以要求worker thread等待,不过这样就等于变成了Synchronous Handler)。因为通常处理一个web request的后台时间需要比较长。假设你每秒只能处理10个用户请求,在同步模式下如果有11个人同时访问你的服务,就有一个人会看到500 Internal Server Error之类的错误消息了。但如果是异步模式,worker thread只要调用BeignProcessRequest,而根据Asynchronous Programming Overview,BeignProcessRequest应该立刻返回(“立刻”的含义是它不应该进行长时间的操作,而应该调用QueueUserWorkItem之类的API将耗时的任务放到新线程里执行),这样worker thread就可以腾出手去接收下一个user request了。
由此引出的问题自然是:当异步操作完成时, ASP.NET是如何知道并做相应处理的。这有一下几种选择:
1) 当调用BeginProcessRequest的时候,ASP.NET可以同时传入一个AsyncCallback的delegate,而在你完成异步操作后,你应该调用这个回调函数来通知ASP.NET。
2) ASP.NET可以不停地查看IAsyncResult (这个是BeginProcessRequest的返回值)IsCompleted属性来确认异步操作是否已经完成了,当然,当你完成异步操作时,你有义务将IsCompleted设成true。
3) ASP.NET也可以等待AsyncWaitHandle的信号,AsyncWaitHandle死IAsyncResult的另一个属性,这个和经典的Win32里waiting on kernel object时类似的。
4) ASP.NET可以直接调用EndProcessRequest。
注意:3) 和 4) 是Asynchronous Programming Overview里规定的标准的blocking execution的方式,也就是说,如果你的主线程在异步操作完成前无法再做任何工作时,它可以通过3) 或者 4)来等待异步操作的完成。
从理论上来说,你应该保证你的IHttpAsyncHandler能满足以上所有4种方式。但现实中,你未必一定如此做。那么哪些是我们必须实现以匹配ASP.NET的要求的呢?或者ASP.NET究竟是如何实现异步调用及返回的呢?
事实上,ASP.NET采用了方法1,也就是说,在调用BeignProcessRequest的时候,ASP.NET传入了一个AsyncCallback,而你应该在完成异步操作后调用这个callback,而在这个AsyncCallback里,ASP.NET又调用了你的EndProcessRequest来做收尾工作。