【C#】對異步請求處理程序IHttpAsyncHandler的理解和分享一個易用性封裝


在asp.net項目中,添加一個【一般處理程序】來處理請求是很自然的事,這樣會得到一個實現自IHttpHandler的類,然后只需在ProcessRequest方法中寫上處理邏輯就行了。但是這樣的一個請求處理程序(下稱ashx)是同步的,就是接待該次請求的線程會一直等待處理完才能解脫,后果就是,如果這個ashx比較耗時,並且同時對它的請求又多的話,服務器需要開啟若干個線程來跑這個ashx,並且這些線程都要各自跑很久才能被收回或挪作它用,如果這樣的ashx還有不少的話,那么對整個服務器資源的開銷是很大的,所以有必要采用IHttpAsyncHandler來實現這種ashx,即異步請求處理程序,異步化以后,線程把請求接進來就完事了,反手就可以去處理其它請求,然后由別的線程硬件來處理具體的任務~取決於任務是CPU消耗型(密集運算,如圖片處理)還是I/O型(數據庫讀寫、網絡訪問等),老實說如果耗時任務總是CPU消耗型,那同步異步在資源消耗上沒什么區別,因為總得有個線程來跑任務,換不換線程意義不大。但總的來說異步化沒壞處,而且萬一對任務類型評估錯誤呢。

改用IHttpAsyncHandler后,多了兩個方法BeginProcessRequest和EndProcessRequest,原有的ProcessRequest事實上已經廢棄,請求不會進入里面,而是改為在BeginProcessRequest中處理請求,原IsReusable屬性功能不變。說回BeginProcessRequest,這是一個典型的傳統異步方法(相對於.net 4.5后的async/await新式異步方法來說),邏輯相比原來的同步方法ProcessRequest有點繞,首先入參除了熟悉的HttpContext外還有兩個,然后還有個IAsyncResult類型的返回值。熟悉APM(異步編程模型)套路的朋友知道該怎么搞,不熟悉的可參看MSDN,要點就是實例化一個實現IAsyncResult的類,在其中異步或起線程執行邏輯,然后返回這個對象。現成的實現IAsyncResult的類在.net 4.0后有Task,但如果項目不到4.0,你還找不到一個可以拿來就用的類,如果要為每個ashx實現一個IAsyncResult,想想都蛋疼,哪怕總共只需實現一個IAsyncResult我都不情願,好在委托這個東西編譯器會為它自動生成異步模型,於是有了下面這個簡單的封裝:

/// <summary>
/// 異步請求處理基類
/// <para>- 子類實現ProcessRequest方法並在其中處理請求</para>
/// <para>- 默認允許實例重用(IsReusable=true),子類可重寫為false</para>
/// </summary>
public abstract class HttpAsyncHandler : IHttpAsyncHandler
{
    readonly Action<HttpContext> _processRequestDel;

    protected HttpAsyncHandler() => _processRequestDel = ProcessRequest;

    /// <summary>
    /// 處理請求
    /// </summary>
    //總是要有個讓子類處理業務邏輯的地方,既然原來的ProcessRequest已廢棄,不如廢物利用
    public abstract void ProcessRequest(HttpContext context);

    /// <summary>
    /// 多次請求是否可以重用實例。默認true
    /// </summary>
    public virtual bool IsReusable => true;

    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) =>
        _processRequestDel.BeginInvoke(context, cb, extraData); //利用ProcessRequest委托的異步能力

    //雖然不End也不會導致異步還沒跑完就返回響應(HttpApplication的實現似乎保證這一點),但異步中拋出的異常會被忽略,所以需要End暴露問題
    public void EndProcessRequest(IAsyncResult result) => _processRequestDel.EndInvoke(result);
}

有了這個封裝好的基類,在寫新的ashx時就可以把IHttpHandler改為HttpAsyncHandler,完了把ProcessRequest方法標成override就行,老ashx也可以經過簡單修改異步化。舉例:

public class FooHandler : HttpAsyncHandler // 替掉IHttpHandler
{
    //加上override
    public override void ProcessRequest(HttpContext context)
    {
        //在這里寫邏輯
        context.Response.Write("OK");
    }
}

需要注意的是IsReusable在HttpAsyncHandler中已改為true,所以如果你的ashx明確需要false,請override該屬性,如:

public override bool IsReusable => false;

對於.net 4.5及以上版本,微軟已經寫好了個HttpTaskAsyncHandler,性質一樣,只不過形式上符合新式的async/await用法,總之目的都是讓開發者可以優雅的使用異步ashx,不必繁瑣的從IHttpAsyncHandler開始。

EOF


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM