IIS可以對ASP.NET網站進行一個資源控制,包括使用的CPU,處理進程數等.但如果想對某些動態網頁面進行一個資源限制,只允許固定線程數量來處理某些動態請求,而不至於在某些情況個別的動態請求把整個站的資源都佔光了.對於這麼小的粒度控制顯然不適合由IIS來做,這個時候就可以通過asp.net提供IHttpAsyncHandler來解決這種事情.
處理結構
由於Asp.net提供了非同步處理Handler,所以可以在Handler的Begin處理方法中把具體對象存放到隊列中,然後根據實際業務的需要來配置1-N個線程來處理相關請求.
IHttpAsyncHandler
public interface IHttpAsyncHandler : IHttpHandler{/// <summary>Initiates an asynchronous call to the HTTP handler.</summary>/// <returns>An <see cref="T:System.IAsyncResult" /> that contains information about the status of the process.</returns>/// <param name="context">An <see cref="T:System.Web.HttpContext" /> object that provides references to intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests. </param>/// <param name="cb">The <see cref="T:System.AsyncCallback" /> to call when the asynchronous method call is complete. If <paramref name="cb" /> is null, the delegate is not called. </param>/// <param name="extraData">Any extra data needed to process the request. </param>IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData);/// <summary>Provides an asynchronous process End method when the process ends.</summary>/// <param name="result">An <see cref="T:System.IAsyncResult" /> that contains information about the status of the process. </param>void EndProcessRequest(IAsyncResult result);}
從代碼來看IHttpAsyncHandler也是從IHttpHandler派生下來,並提供了Begin和End相關方法.
對已有頁面進行非同步封裝
如果經常用IHttpHandler的朋友應該比較清楚這東西用於描述一個頁面請求的,包括我們的aspx,而aspx預設處理的則是一個IHttpHandlerFactory實現System.Web.UI.PageHandlerFactory.通簡單地繼承System.Web.UI.PageHandlerFactory就可以讓原來的aspx請求返回對應的非同步HttpHandler.
public class CustomPageFactory : System.Web.UI.PageHandlerFactory { static CustomPageFactory() { } public override IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path) { AspxAsyncHandler handler = new AspxAsyncHandler(base.GetHandler(context, requestType, virtualPath, path)); return handler; } }
PageFactory實現後只需要簡單地配置一個web.config檔案就可以讓現有的aspx處理由非同步Handler來處理.
<handlers> <add name="custompage" verb="*" path="*.aspx" type="WebApp.Code.CustomPageFactory,WebApp"/></handlers>
隊列化處理
制定隊列的目的非常簡單就是有序可控地去處理一些工作,可以通過BeginProcessRequest的執行把請求先存放到了列中
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) { AspxAsyncResult result = new AspxAsyncResult(context, mHandler, cb); G_TaskQueue.Add(result); return result; }
制定線程處理
可以根據實際情況開啟1-N個線程來處理隊列中的工作.
private void OnRun(object state) { while (true) { AspxAsyncResult asyncResult = Pop(); if (asyncResult != null) { asyncResult.Execute(); } else { System.Threading.Thread.Sleep(10); } } }
以上是固定線程去進行處理,但這樣的設計不好的地方就是沒有請求的時候線程會不停地做sleep工作,其實可以根據實際情況使用線程池來完成,具體就看情況來設計了.
總結
通過以上設計就可以輕易地對某些頁面請求進行一個資源控制.如果比較關心具體實現的朋友可以查看
http://blog.henryfan.net/post/2012/11/21/%E5%AE%9E%E7%8E%B0%E5%AF%B9%E7%8E%B0%E6%9C%89%E7%9A%84aspx%E8%AF%B7%E6%B1%82%E8%BF%9B%E8%A1%8C%E5%BC%82%E6%AD%A5%E9%98%9F%E5%88%97%E6%8E%A7%E5%88%B6%E5%A4%84%E7%90%86.aspx