2014年11月4日 星期二

非同步Action

非同步Action方法有兩種定義方式
1:XxxAsync/XxxCompleted
public class HomeController : AsyncController
{
    // GET : /Home/Article (在繼承自AsyncController裡的Controller才能使用Article當Action名稱)
    // 非同步操作
    public void ArticleAsync()
    {
        // 開始非同步的時候,先使用 AsyncManager.OutstandingOperations 取得一個 OperationCounter 對象,
        // 然後調用 Increment() 方法向系統發一個非同步操作開始的通知,OperationCounter 會 +1
        // 結束的時候調用 Decrement(),OperationCounter 會 -1,在發法結束時,當OperationCounter 為 0 才會自動調用 ArticleCompleted() 方法

        AsyncManager.OutstandingOperations.Increment();
        string path = ControllerContext.HttpContext.Server.MapPath(string.Format(@"\Project_Readme.html"));
        StreamReader reader = new StreamReader(path);
        reader.ReadToEndAsync().ContinueWith(Task =>
        {
            AsyncManager.Parameters["content"= Task.Result; // 保存要給 ArticleCompleted() 方法的參數,必須與參數同名("content")才能自動匹配
            AsyncManager.OutstandingOperations.Decrement(); // 自動調用 ArticleCompleted() 方法
            reader.Close();
        });
    }
 
    // 非同步最終請求的響應,ArticleAsync 方法的回調
    // content 參數來自 AsyncManager.Parameters["content"]
    public ActionResult ArticleCompleted(string content)
    {
        return Content(content);
    }
}
以 XxxAsync/XxxCompleted 方式定義非同步 Action 方法,表示說必需得為一個 Action 定義兩個方法(實際上可以通過一個方法完成 Action 非同步的定義,那就是讓 Action 方法返回一個代表非同步操作的 Task 對象)。

這方式只能出現在繼承自 AsyncController 的 Controller 中,但是 Task 方式沒有限制(保留 AsyncController 這個抽象類主要是為了實現對 ASP.NET MVC 3 的向後兼容)。

2:Task
public Task<ActionResult> Article()
{
    string path = ControllerContext.HttpContext.Server.MapPath(string.Format(@"\Project_Readme.html"));
    StreamReader reader = new StreamReader(path);
    return reader.ReadToEndAsync().ContinueWith<ActionResult>(task =>
    {
        reader.Close();
        return Content(task.Result);
    });
}

由於 Action 返回一個 Task<ActionResult> 對象,所以可以利用 async/await 關鍵字 (C# 5.0) 直接將其標示為非同步


public async Task<ActionResult> Article()
{
    string path = ControllerContext.HttpContext.Server.MapPath(string.Format(@"\Project_Readme.html"));
    using (StreamReader reader = new StreamReader(path))
    {
        return Content(await reader.ReadToEndAsync());
    }
}



沒有留言: