2013-03-10 27 views
1

我在MVC 4應用程序的控制器操作:何時應該將操作標記爲異步?

public ActionResult Index() 
    { 
     GetStartedModel gsModel = new GetStartedModel(); 

     return View(gsModel); 
    } 

和視圖模型:

public class GetStartedModel 
{ 
    public IEnumerable<SelectListItem> listA { get; set; } 
    public IEnumerable<SelectListItem> listB { get; set; } 

    public GetStartedModel() 
    { 
     TestDataWebServiceHelper service = new TestDataWebServiceHelper(); 
     this.GetData(service); 
    } 

    private async void SetData(TestDataWebServiceHelper service) 
    { 
     listA = await this.SetListA(service); 
     listB = await this.SetListB(service); 
    } 

    private async Task<IEnumerable<SelectListItem>> SetListA(TestDataWebServiceHelper service) 
    { 
     List<String> rawList = new List<String>(); 
     rawList = await service.GetValuesAsync("json"); 
     return rawList.Select(x => new SelectListItem { Text = x, Value = x }); 
    } 

    private async Task<IEnumerable<SelectListItem>> SetListB(TestDataWebServiceHelper service) 
    { 
     List<String> rawList = new List<String>(); 
     rawList = await service.GetValuesAsync("json"); 
     return rawList.Select(x => new SelectListItem { Text = x, Value = x }); 
    } 
} 

當我把這個控制器動作我收到以下錯誤:

An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>.

所以,問題:

  1. 我應該以某種方式將控制器或動作或頁面本身標記爲異步以允許此模型初始化?
  2. 是否有可能將所有初始化邏輯封裝到viewmodel,而不是將其彈出到控制器?
  3. 該錯誤的原因是什麼?看起來像它與WebForms相關,但我使用Razor引擎。是

回答

5

有在你的代碼的兩個問題:

  1. 你不應該從這樣的構造async void操作。事實上,你通常不應該從構造函數開始任何async操作,你也不應該使用async void方法(事件處理程序除外)。

    我認爲你的情況,async工廠方法而不是構造是很有道理的:

    private GetStartedModel() 
    {} 
    
    public static async Task<GetStartedModel> Create() 
    { 
        var service = new TestDataWebServiceHelper(); 
        var result = new GetStartedModel(); 
        listA = await result.SetListA(service); 
        listB = await result.SetListB(service); 
        return result; 
    } 
    

    有關詳細信息,請參閱Stephen Cleary's post on async constructors

  2. 你需要讓你的控制器動作async太:

    public async Task<ActionResult> Index() 
    { 
        var gsModel = await GetStartedModel.Create() 
    
        return View(gsModel); 
    } 
    
+0

'Create()'應該返回Task 嗎? – Anthony 2013-03-10 18:04:18

+0

@Anthony它應該,謝謝,修正。 – svick 2013-03-10 18:11:36

+0

非常感謝。這對我來說非常合適。 – Anthony 2013-03-10 18:16:35

0

有一些事情要對「異步」護理如下:

  • 的方法只能是「異步」時需要等待行動它是通過編寫的代碼執行
  • 如果在該方法中沒有什麼需要「等待」,則該方法不應聲明爲「異步」。
  • 是否有任何事件(或其他事件處理程序),以被標記爲異步然後返回類型應該是「無效」或任何具體的返回類型
  • 但如果任何其他(普通)方法應標記爲「異步」,那麼返回類型應該是TaskTask< return-type >

現在來到你的問題,

  • 絕對可以標記「控制器」,「事件」 &「頁」爲異步(我 不該死的肯定標誌着頁面async coz我從來沒有使用它) 並由那些方法將採取休息,直到行動將 執行完全寫在該方法。
  • 而這就是在viewModel中封裝邏輯的整個初始化 的實際系統。
    • 爲了製作一個Floder,將其命名爲「ViewModels」並將所有viewModel代碼放在該文件夾中,並在需要時使用該代碼。

你應該把你的代碼在一個視圖模型:

private async void SetData(TestDataWebServiceHelper service) 
{ 
    listA = await this.SetListA(service); 
    listB = await this.SetListB(service); 
} 

private async Task<IEnumerable<SelectListItem>> SetListA(TestDataWebServiceHelper service) 
{ 
    List<String> rawList = new List<String>(); 
    rawList = await service.GetValuesAsync("json"); 
    return rawList.Select(x => new SelectListItem { Text = x, Value = x }); 
} 

private async Task<IEnumerable<SelectListItem>> SetListB(TestDataWebServiceHelper service) 
{ 
    List<String> rawList = new List<String>(); 
    rawList = await service.GetValuesAsync("json"); 
    return rawList.Select(x => new SelectListItem { Text = x, Value = x }); 
} 

,然後你應該把它需要的時候。

(希望這有助於...)

+0

你不能有'任務<>',我想你的意思只是'Task'。 – svick 2013-03-10 12:08:53

+0

雅我只是說... 對不起, – 2013-03-10 12:32:58

+0

好吧,這是足夠明確的解釋,但我仍然不明白爲什麼我在創建GetStartedModel的新實例時收到該錯誤。 – Anthony 2013-03-10 14:41:34