我正在构建我的第一个真正的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传递给view ...
提前致谢
编辑:我已尝试使用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:由于我被告知创建新任务不是正确的事情,我从代码中选择了第一个建议的方法removin AdminDMSEntities类。感谢Darin帮助我:)
答案 0 :(得分: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);
}
}