2015-02-23 111 views
0

環境:ASP.NET MVC 5時,SQL Server異步方法掛在asp.net

這裏是我的方法是從數據庫返回當前用戶的配置文件:

public static ProfileModel getCurrentProfile(HttpContextBase ctx) { 
    User user = AccountController.getUser(ctx); 

    Task<ProfileModel> model = ProfileModel.getValue(user.UserID); 
    model.Wait(); 
    return model.Result; 
} 

在執行時,model.Wait()剛剛掛起向上。

我已經閱讀了幾篇關於死鎖的文章,並使用ConfigAwait(false)來處理這種情況。但是,我需要調用這個方法的地方很多。我想如果我以正確的方式解決問題,我可能完全避免撥打ConfigAwait()

這裏是我如何用我的index.cshtml文件的方法:

Members.Models.ProfileModel userModel = HomeController.getCurrentProfile(Context); 
Html.RenderPartial("_PartialPublicProfile", userModel); 

文件_PartialPublicProfile需要ProfileModel實例中傳遞是否有可能在Task<ProfileModel>實例作爲參數傳遞?

或者,有沒有更好的方法來解決問題?問候。

+1

ProfileModel.getValue在「掛起」時發生了什麼? – Will 2015-02-23 19:24:19

+0

爲什麼在視圖中調用一個函數,而不是調用控制器動作中的函數,並將它作爲模型的一部分或視圖包傳遞給視圖?在動作中調用getCurrentProfile時會發生什麼? – 2015-02-23 19:32:41

回答

2

你基本上試圖同步運行一個異步任務。你必須小心小心你如何做,否則你的應用程序可以並將掛起。

在實體框架6中,現在有同步和異步數據訪問方法,但重要的是,同步版本同步調用異步版本。爲了解決這個問題,EF團隊使用以下內部幫助類。我會建議實施此作爲自己的助手類,然後在所有情況下使用它,你需要調用一個異步方法同步:

public static class AsyncHelper 
{ 
    private static readonly TaskFactory _myTaskFactory = new 
     TaskFactory(CancellationToken.None, 
        TaskCreationOptions.None, 
        TaskContinuationOptions.None, 
        TaskScheduler.Default); 

    public static TResult RunSync<TResult>(Func<Task<TResult>> func) 
    { 
     return AsyncHelper._myTaskFactory 
      .StartNew<Task<TResult>>(func) 
      .Unwrap<TResult>() 
      .GetAwaiter() 
      .GetResult(); 
    } 

    public static void RunSync(Func<Task> func) 
    { 
     AsyncHelper._myTaskFactory 
      .StartNew<Task>(func) 
      .Unwrap() 
      .GetAwaiter() 
      .GetResult(); 
    } 
} 

所以,在這裏您的特定情況下,您的代碼將變爲:

public static ProfileModel getCurrentProfile(HttpContextBase ctx){ 
    User user = AccountController.getUser(ctx); 

    var model = AsyncHelper.RunSync<ProfileModel>(() => ProfileModel.getValue(user.UserID)); 
    return model; 
}