2013-04-22 45 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