簡體   English   中英

操作完成前MVC4 + async / await +返回響應

[英]MVC4 + async/await + return response before action completes

在我的MVC4應用程序中,我需要添加一個控制器來上傳和處理大文件。 文件上傳后,我需要立即啟動該文件的異步處理並將響應返回給瀏覽器,而無需等待處理完成。

顯然我可以手動啟動一個新線程來處理文件,但我想知道是否可以使用.net 4.5引入的async / await機制來實現這個場景

為了測試這個概念,我嘗試過這樣的事情:

public async Task<ActionResult> Test()
{
    TestAsync();
    return View("Test");
}

public async void TestAsync()
{
    await LongRunning();
}

private Task<int> LongRunning()
{
    return Task<int>.Factory.StartNew(() => Pause());
}

private int Pause()
{
    Thread.Sleep(10000);
    return 3;
}

異步機制似乎一般工作:當我調試代碼時,我點擊“返回視圖(”測試“);” 行“返回3”之前的行。 但是,瀏覽器僅在Pause方法完成后才會收到響應。

這看起來像常規異步控制器(具有Async和Completed方法的控制器)。 有沒有辦法在控制器中為我的場景使用async / await?

顯然我可以手動啟動一個新線程來處理文件,但我想知道是否可以使用.net 4.5引入的async / await機制來實現這個場景

不,你不能,因為async不會改變HTTP協議

Svick和James已經發布了正確的答案作為評論,為方便起見,我在下面重復:

IIS可以隨時回收您的應用程序。

如果您有長時間運行的事情要求異步,請在其他地方執行。 “典型”是一個持久性隊列(MSMQ,Azure,RabbitMQ等),其他東西(Windows服務,由任務調度程序運行的exe,使用Quartz.net的應用程序等)處理它們。

總而言之,HTTP為您提供了一個請求和一個響應( async - 以及其他任何內容 - 不會改變這一點)。

ASP.NET是圍繞HTTP請求設計的(並假設“如果沒有未完成的請求,則可以安全地停止此網站”)。 可以啟動一個新的線程,並將你的上傳保存在內存中(這是最簡單的方法),但強烈建議不要這樣做。

根據您的情況,我建議您遵循James的建議:

  • 上載完成后,將上載保存到永久存儲(例如,Azure隊列),並將“票證”返回給瀏覽器。
  • 讓其他進程(例如,Azure輔助角色)處理隊列,最終將其標記為完成。
  • 讓瀏覽器使用其“票證”輪詢服務器。 服務器使用“票證”在持久存儲中查找文件,並返回它是否完整。

這有一些變化(例如,使用SignalR在處理完成時通知瀏覽器),但一般架構是相同的。

這很復雜,但這是正確的方法。

您的代碼中有錯誤。 您必須等待操作中對TestAsync的調用。 如果不這樣做,它只返回一個“任務”對象而不運行任何東西。

public async Task<ActionResult> Test()
{
    await TestAsync();
    return View("Test");
}

並且在異步方法中睡眠的正確方法是調用

await Task.Delay(10000);

您必須更改TestAsync的簽名:如果方法返回void,則不應將方法標記為異步。 它必須返回Task。 保留返回void以與.net事件兼容。

public async Task TestAsync()
{
    await LongRunning();
}

方法體是相同的。

你的LongRunning方法同步睡眠10秒。 改變它,以便睡眠發生在任務中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM