0

Environment: ASP.NET MVC 5, SQL Server

Here is my method that returns current user's profile from the database:

public static ProfileModel getCurrentProfile(HttpContextBase ctx) {
   User user = AccountController.getUser(ctx);

   Task<ProfileModel> model = ProfileModel.getValue(user.UserID);
   model.Wait();
   return model.Result;
}

Upon execution, model.Wait() just hangs up.

I have read several articles about deadlocks and using ConfigAwait(false) for such situations. However, there would be lot of places I would need to call this method. I am thinking if I fix it the right way, I may be able to avoid ConfigAwait() calls altogether.

Here is how I am using the method in my index.cshtml file:

Members.Models.ProfileModel  userModel = HomeController.getCurrentProfile(Context);
Html.RenderPartial("_PartialPublicProfile", userModel);

File _PartialPublicProfile requires ProfileModel instance to be passed in. Is it possible to pass in Task<ProfileModel> instance as a parameter?

Or, is there a better way to solve the problem? Regards.

2
  • 1
    What's going on in ProfileModel.getValue when it "hangs"? Commented Feb 23, 2015 at 19:24
  • Why are you calling a function in your view instead of calling the function in the controller action and passing it to the view as part of the model or in the viewbag? What happens when you call getCurrentProfile in the action? Commented Feb 23, 2015 at 19:32

1 Answer 1

2

You're essentially trying to run an async task synchronously. You have to be very careful about how you do that or else your application can and will hang.

In Entity Framework 6, there are now sync and async data access methods, but importantly, the sync versions call the async versions synchronously. To pull this off the EF team uses the following internal helper class. I would recommend implementing this as your own helper class, and then using it in all scenarios where you need to call an asynchronous method synchronously:

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();
    }
}

So, in your particular scenario here, you code would change to:

public static ProfileModel getCurrentProfile(HttpContextBase ctx){
   User user = AccountController.getUser(ctx);

   var model = AsyncHelper.RunSync<ProfileModel>(() => ProfileModel.getValue(user.UserID));
   return model;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.