1

我正在构建我的第一个真正的 MVC4 应用程序,我遇到了以下问题。

我有一个“用户”类的模型。它的数据是通过异步调用webservice获取的:

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 中使用 tis 类,如下所示:

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 个)。

EDIT2:因为我被告知创建新任务不是正确的做法,所以我采用了第一个建议的方法,从代码中删除了 AdminDMSEntities 类。我感谢达林帮助我:)

4

1 回答 1

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,您甚至可以利用 newasync关键字进一步简化异步代码。如果您将数据访问层重构为新模式(即返回任务),这是可能的:

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);
    }
}
于 2013-04-22T09:08:05.263 回答