2013-04-22 52 views
1

我正在構建我的第一個真正的MVC4應用程序,並遇到以下問題。MVC 4 web應用程序異步調用webservice

我有一個「用戶」類的模型。它的數據通過異步調用獲得Web服務:

public sealed class AdminDMSEntities 
{ 
    public List<User> UserList { get; private set; } 

    public AdminDMSEntities() 
    { 
     this.UserList = new List<User>(0); 
     ServiceClient client = new ServiceClient(); 
     client.GetUsersCompleted += (s, e) => 
     { 
      if (e.Result == null) 
       throw new ArgumentNullException("No users were retrieved"); 

      UserList = new List<User>(0); 
      e.Result.ForEach(w => this.UserList.Add(new User(w.Guid, w.TrusteeType, w.Username, w.Email, w.LastLogin, w.PasswordChanged, w.IsUsingTempPassword)));    
     }; 

     client.GetUsersAsync(); 
    }   
} 

我打算使用這個類,我會用從派生的DbContext(如果我可以使用實體框架,我廣東話)類。到目前爲止,我只有班上的用戶。

我使用那朵類UsersController這樣的:

public class UsersController : Controller 
{ 
    private AdminDMSEntities adminEntities = new AdminDMSEntities(); 
    // 
    // GET: /User/ 

    public ActionResult Index() 
    { 
     return View(adminEntities.UserList); 
    } 
} 

的問題是,我將最終出現InvalidOperationException,因爲控制器不等待異步調用完成並通過在UserList的觀點之前,它是正確填充用戶。

我可以暫時調用同步,但很可能以後我會被迫使用異步調用,所以我想知道如何確保該控制器將等待異步調用完成通過之前的UserList查看...

在此先感謝

編輯:我曾嘗試與AsyncController的方法如下所列,目前我已經加入這個AdminDMS實體類:

public static async Task<AdminDMSEntities> AdminDMSEntitiesAsync() 
    { 
     AdminDMSEntities result = null; 
     Task<AdminDMSEntities> getUsersAsyncTask = Task.Factory.StartNew(() => new AdminDMSEntities()); 
     await getUsersAsyncTask; 
     return result; 
    } 

這就是變化到控制器:

public class UsersController : AsyncController 
{ 
    private AdminDMSEntities adminEntities = null; 
    // 
    // GET: /User/ 

    public async Task<ActionResult> Index() 
    { 
     if (adminEntities == null) 
     { 
      adminEntities = await AdminDMSEntities.AdminDMSEntitiesAsync(); 
     } 
     return View(adminEntities.UserList); 
    } 
} 

結果是adminEntities被包含類的一個實例,但也有沒有用戶在列表中(應該有11)。編輯2:由於我被告知創建新任務不是正確的事情,所以我從代碼中選擇了第一個建議的方法removin AdminDMSEntities類。感謝Darin幫助我:)

回答

1

您可以使用asynchronous controller。這個想法是讓你的控制器來自AsyncController類,而不是Controller類。此類提供允許您執行異步操作的方法。

例如:

public class MyController: AsyncController 
{ 
    public void IndexAsync() 
    { 
     AsyncManager.OutstandingOperations.Increment(); 
     var client = new SomeClient(); 
     client.GetUsersCompleted += (s, e) => 
     { 
      UserList = new List<User>(); 
      AsyncManager.Parameters["users"] = e.Result.Select(
       w => new User(
        w.Guid, 
        w.TrusteeType, 
        w.Username, 
        w.Email, 
        w.LastLogin, 
        w.PasswordChanged, 
        w.IsUsingTempPassword 
       ) 
      ) 
      .ToList(); 
      AsyncManager.OutstandingOperations.Decrement();    
     }; 
     client.GetUsersAsync(); 
    } 

    public ActionResult IndexCompleted(IEnumerable<User> users) 
    { 
     return View(users); 
    } 
} 

,如果你使用的是.NET 4.5,你甚至可以利用新async關鍵字進一步簡化異步代碼的優勢。如果您將數據訪問層重構爲新模式(即返回任務),則這是可能的:

public class MyController: AsyncController 
{ 
    public async Task<ActionResult> Index() 
    { 
     var client = new SomeClient(); 
     var users = await client.GetUsersAsync().Select(
      w => new User(
       w.Guid, 
       w.TrusteeType, 
       w.Username, 
       w.Email, 
       w.LastLogin, 
       w.PasswordChanged, 
       w.IsUsingTempPassword 
      ) 
     ) 
     .ToList(); 
     return View(users); 
    } 
} 
+0

它看起來像我需要的東西,但我不能讓它運行。我的GetUsersAsync方法來自於自動生成的服務引用,它返回「void」,所以我使用了我的原始文章中的構造函數的代碼,並且我必須使用'await Task.Factory.StartNew(()=> client.GetUsersAsync ());'不幸的是null仍然被傳遞給視圖。 – Erchi 2013-04-22 10:28:38

+0

你不應該創建一個新的任務。您應該直接在控制器操作中使用自動生成的客戶端實例。並訂閱我的答案中顯示的'GetUsersCompleted'事件。 – 2013-04-22 10:42:58

+0

我刪除了以前的評論,我剛剛找到自動生成方法的定義。我會嘗試你的方法,然後回覆你 – Erchi 2013-04-22 10:54:47