日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
為ASP.NET MVC擴(kuò)展異步Action功能(下)

編輯推薦:為ASP.NET MVC擴(kuò)展異步Action功能(上)

執(zhí)行Action方法

對于執(zhí)行同步Action的SyncMvcHandler,其實(shí)現(xiàn)十分簡單而直接:

public class SyncMvcHandler : IHttpHandler, IRequiresSessionState
{
    public SyncMvcHandler(
        IController controller,
        IControllerFactory controllerFactory,
        RequestContext requestContext)
    {
        this.Controller = controller;
        this.ControllerFactory = controllerFactory;
        this.RequestContext = requestContext;
    }

    public IController Controller { get; private set; }
    public RequestContext RequestContext { get; private set; }
    public IControllerFactory ControllerFactory { get; private set; }

    public virtual bool IsReusable { get { return false; } }

    public virtual void ProcessRequest(HttpContext context)
    {
        try
        {
            this.Controller.Execute(this.RequestContext);
        }
        finally
        {
            this.ControllerFactory.ReleaseController(this.Controller);
        }
    }
}

而對于異步Action,我之前一直思考著怎么將框架的默認(rèn)實(shí)現(xiàn),也就是單個(gè)方法調(diào)用,轉(zhuǎn)化成兩個(gè)方法(BeginXxx/EndXxx)調(diào)用。曾經(jīng)我想過自己實(shí)現(xiàn)一個(gè)新的ActionInvoker,但是這就涉及到了大量的工作,尤其是如果希望保持框架現(xiàn)有的功能(ActionFilter,ActionSelector等等),最省力的方法可能就是繼承ControllerActionInvoker,并設(shè)法使用框架已經(jīng)實(shí)現(xiàn)的各種輔助方法。但是在分析了框架代碼之后我發(fā)現(xiàn)復(fù)用也非常困難,舉例來說,ControllerActionInvoker判定一個(gè)方法為Action的依據(jù)之一是這個(gè)方法返回的是ActionResult類型或其子類,這意味著我無法直接使用這個(gè)方法來獲取一個(gè)返回IAsyncResult的BeginXxx方法;同理,對于查找EndXxx方法,我可能需要在請求名為Abc的異步Action時(shí),將EndAbc作為查找依據(jù)交由現(xiàn)成的方法來查詢——但是,如果又有一個(gè)請求是直接針對一個(gè)名為EndAbc的同步Action的那又怎么辦呢?

由于這些問題存在,我在去年設(shè)法實(shí)現(xiàn)異步Action時(shí)幾乎重寫了整個(gè)ActionInvoker——其復(fù)雜程度可見一斑。而且那個(gè)實(shí)現(xiàn)對于一些特殊情況的處理依舊不甚友好,需要開發(fā)人員在一定程度上做出妥協(xié)。這個(gè)實(shí)現(xiàn)在TechED 2008 China的Session中公布時(shí)我就承認(rèn)它并不能讓我滿意,建議大家不要將其投入生產(chǎn)環(huán)境中。而現(xiàn)在的實(shí)現(xiàn),則非常順利地解決了整個(gè)問題。雖然從理論上講還不夠“完美”,雖然還做出了一些讓步。

帶來如此多問題的原因就在于我們在設(shè)法顛覆框架內(nèi)部的關(guān)鍵性設(shè)計(jì),也就是從單一的Action方法調(diào)用,轉(zhuǎn)變?yōu)椤胺螦PM的”二段式調(diào)用。等等,您是否感覺到了解決問題的關(guān)鍵?沒錯(cuò),那就是“符合APM的”。APM要求我們將一個(gè)行為分為BeginXxx和EndXxx兩個(gè)方法,可是既然ASP.NET MVC框架只能讓我們返回一個(gè)ActionResult對象……那么我們?yōu)槭裁床辉谶@個(gè)對象里包含方法的引用——也就是一個(gè)委托對象呢?這雖然不符合正統(tǒng)的APM簽名,但是完全可行,不是嗎?

public class AsyncActionResult : ActionResult
{
    public AsyncActionResult(
        IAsyncResult asyncResult,
        Func<IAsyncResult, ActionResult> endDelegate)
    {
        this.AsyncResult = asyncResult;
        this.EndDelegate = endDelegate;
    }

    public IAsyncResult AsyncResult { get; private set; }

    public Func<IAsyncResult, ActionResult> EndDelegate { get; private set; }

    public override void ExecuteResult(ControllerContext context)
    {
        context.Controller
            .SetAsyncResult(this.AsyncResult)
            .SetAsyncEndDelegate(this.EndDelegate);
    }
}

由于在Action方法中可以調(diào)用BeginXxx方法,我們在AsyncActionResult中只需保留Begin方法返回的IAsyncResult,以及另一個(gè)對于EndXxx方法的引用。在AsyncActionResult的ExecuteResult方法中將會保存這兩個(gè)對象,以便在AsyncMvcHandler的EndProcessRequest方法中重新獲取并使用。根據(jù)“慣例”,我們還需要定義一個(gè)擴(kuò)展方法,方便開發(fā)人員在Action方法中返回一個(gè)AsyncActionResult。具體實(shí)現(xiàn)非常容易,在這里就展示一下異步Action的編寫方式:

[AsyncAction]
public ActionResult AsyncAction(AsyncCallback asyncCallback, object asyncState)
{
    SqlConnection conn = new SqlConnection("...;Asynchronous Processing=true");
    SqlCommand cmd = new SqlCommand("WAITFOR DELAY '00:00:03';", conn);
    conn.Open();

    return this.Async(
        cmd.BeginExecuteNonQuery(asyncCallback, asyncState),
        (ar) =>
        {
            int value = cmd.EndExecuteNonQuery(ar);
            conn.Close();
            return this.View();
        });
}

至此,似乎AsyncMvcHandler也無甚秘密可言了:

public class AsyncMvcHandler : IHttpAsyncHandler, IRequiresSessionState
{
    public AsyncMvcHandler(
        Controller controller,
        IControllerFactory controllerFactory,
        RequestContext requestContext)
    {
        this.Controller = controller;
        this.ControllerFactory = controllerFactory;
        this.RequestContext = requestContext;
    }

    public Controller Controller { get; private set; }
    public RequestContext RequestContext { get; private set; }
    public IControllerFactory ControllerFactory { get; private set; }
    public HttpContext Context { get; private set; }

    public IAsyncResult BeginProcessRequest(
        HttpContext context,
        AsyncCallback cb,
        object extraData)
    {
        this.Context = context;
        this.Controller.SetAsyncCallback(cb).SetAsyncState(extraData);

        try
        {
            (this.Controller as IController).Execute(this.RequestContext);
            return this.Controller.GetAsyncResult();
        }
        catch
        {
            this.ControllerFactory.ReleaseController(this.Controller);
            throw;
        }
    }

    public void EndProcessRequest(IAsyncResult result)
    {
        try
        {
            HttpContext.Current = this.Context;
            ActionResult actionResult = this.Controller.GetAsyncEndDelegate()(result);
            if (actionResult != null)
            {
                actionResult.ExecuteResult(this.Controller.ControllerContext);
            }
        }
        finally
        {
            this.ControllerFactory.ReleaseController(this.Controller);
        }
    }
}

在BeginProcessRequest方法中將保存當(dāng)前Context——這點(diǎn)很重要,HttpContext.Current是基于CallContext的,一旦經(jīng)過一次異步回調(diào)HttpContext.Current就變成了null,我們必須重設(shè)。接著將接收到的AsyncCallback和AsyncState保留,并使用框架中現(xiàn)成的Execute方法執(zhí)行控制器。當(dāng)Execute方法返回時(shí)一整個(gè)Action方法的調(diào)用流程已經(jīng)結(jié)束,這意味著其調(diào)用結(jié)果——即IAsyncResult和EndDelegate對象已經(jīng)保留。于是將IAsyncResult對象取出并返回。至于EndProcessRequest方法,只是將BeginProcessRequest方法中保存下來的EndDelegate取出,調(diào)用,把得到的ActionResult再執(zhí)行一遍即可。

以上的代碼只涉及到普通情況下的邏輯,而在完整的代碼中還會包括對于Action方法被某個(gè)Filter終止或替換等特殊情況下的處理。此外,無論在BeginProcessRequest還是EndProcessRequest中都需要對異常進(jìn)行合適地處理,使得Controller Factory能夠及時(shí)地對Controller對象進(jìn)行釋放。

#p#

ModelBinder支持

其實(shí)您到目前為止還不能使用異步Action,因?yàn)槟鷷l(fā)現(xiàn)方法的AsyncCallback參數(shù)得到的永遠(yuǎn)是null。這是因?yàn)槟J(rèn)的Model Binder無法得知如何從一個(gè)上下文環(huán)境中得到一個(gè)AsyncCallback對象。這一點(diǎn)倒非常簡單,我們只需要構(gòu)造一個(gè)AsyncCallbackModelBinder,而它的BindModel方法僅僅是將AsyncMvcHandler.BeginProcessRequest方法中保存的AsyncCallback對象取出并返回:

public sealed class AsyncCallbackModelBinder : IModelBinder
{
    public object BindModel(
        ControllerContext controllerContext,
        ModelBindingContext bindingContext)
    {
        return controllerContext.Controller.GetAsyncCallback();
    }
}

其使用方式,便是在應(yīng)用程序啟動時(shí)將其注冊為AsyncCallback類型的默認(rèn)Binder:

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
    ModelBinders.Binders[typeof(AsyncCallback)] = new AsyncCallbackModelBinder();
}

對于asyncState參數(shù)您也可以使用類似的做法,不過這似乎有些不妥,因?yàn)閛bject類型實(shí)在過于寬泛,并不能明確代指asyncState參數(shù)。事實(shí)上,即使您不為asyncState設(shè)置binder也沒有太大問題,因?yàn)閷τ谝粋€(gè)異步ASP.NET請求來說,其asyncState永遠(yuǎn)是null。如果您一定要指定一個(gè)binder,我建議您在每個(gè)Action方法的asyncState參數(shù)上標(biāo)記如下的Attribute,它和AsyncStateModelBinder也已經(jīng)被一并建入項(xiàng)目中了:

[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
public sealed class AsyncStateAttribute : CustomModelBinderAttribute
{
    private static AsyncStateModelBinder s_modelBinder = new AsyncStateModelBinder();
    public override IModelBinder GetBinder()
    {
        return s_modelBinder;
    }
}

使用方式如下:

[AsyncAction]
public ActionResult AsyncAction(AsyncCallback cb, [AsyncState]object state) { ... }

其實(shí),基于Controller的擴(kuò)展方法GetAsyncCallback和GetAsyncState均為公有方法,您也可以讓Action方法不接受這兩個(gè)參數(shù)而直接從Controller中獲取——當(dāng)然這種做法降低了可測試性,不值得提倡。

限制和缺點(diǎn)

如果這個(gè)解決方案沒有缺陷,那么相信它已經(jīng)被放入ASP.NET MVC 1.0中,而輪不到我在這里擴(kuò)展一番了。目前的這個(gè)解決方案至少有以下幾點(diǎn)不足:

1. 沒有嚴(yán)格遵守.NET中的APM模式,雖然不影響功能,但這始終是一個(gè)遺憾。

2. 由于利用了框架中的現(xiàn)成功能,所有的Filter只能運(yùn)行在BeginXxx方法上。

3. 由于EndXxx方法和最終ActionResult的執(zhí)行都沒有Filter支持,因此如果在這個(gè)過程中拋出了異常,將無法進(jìn)入ASP.NET MVC建議的異常處理功能中。

根據(jù)ASP.NET MVC框架的Roadmap,ASP.NET MVC框架1.0之后的版本中將會支持異步Action,相信以上這些缺陷到時(shí)候都能被彌補(bǔ)。不過這就需要大量的工作,這只能交給ASP.NET MVC團(tuán)隊(duì)去慢慢執(zhí)行了。事實(shí)上,您現(xiàn)在已經(jīng)可以在ASP.NET MVC RC源代碼的MvcFutures項(xiàng)目中找到異步Action處理的相關(guān)內(nèi)容。它添加了IAsyncController,AsyncController,IAsyncActionInvoker,AsyncControllerActionInvoker等許多擴(kuò)展。雖說它們都“繼承”了現(xiàn)有的類,但是與我之前的判斷相似,如AsyncControllerActionInvoker幾乎完全重新實(shí)現(xiàn)了一遍ActionInvoker中的各種功能——我還沒有仔細(xì)閱讀代碼,因此無法判斷出這種設(shè)計(jì)是否優(yōu)秀,只希望它能像ASP.NET MVC本身那樣的簡單和優(yōu)雅。

【編輯推薦】

  1. 為ASP.NET MVC擴(kuò)展異步Action功能(上)
  2. 詳解ASP.NET MVC的請求生命周期
  3. ASP.NET MVC實(shí)例和新RC版本中視圖方面的改進(jìn)
  4. ASP.NET MVC框架視頻教程

當(dāng)前標(biāo)題:為ASP.NET MVC擴(kuò)展異步Action功能(下)
地址分享:http://www.5511xx.com/article/cdshgds.html