环境:ASP.NET MVC 5,SQL Server
这是我从数据库中返回当前用户配置文件的方法:
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>
实例作为参数传入?
或者,有没有更好的方法来解决问题?问候。
答案 0 :(得分:2)
您实际上是在尝试同步运行异步任务。您必须非常小心如何做到这一点,否则您的应用程序可以并且将会挂起。
在Entity Framework 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;
}