挂起在asp.net中的异步方法

时间:2015-02-23 19:20:35

标签: asp.net-mvc

环境: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>实例作为参数传入?

或者,有没有更好的方法来解决问题?问候。

1 个答案:

答案 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;
}