0

TL;DR: I would like to know how I can get the return value from a method that returns Task<T> when invoked from an ASP.Net MVC4 Controller's ActionResult method. Code snippets below.

Question Details:
I'm using the Instasharp Library on github.

Here's the Search method that returns Task<UserResponse>. This is defined in the Instasharp Library.

/// <summary>
/// Search for a user by name.
/// <para>
/// <c>Requires Authentication: False</c>
/// </para>
/// </summary>
/// <param name="searchTem">A query string.</param>
/// <param name="count">Number of users to return.</param>
/// <returns>UsersResponse</returns>
public Task<UsersResponse> Search(string searchTerm, int? count = null) {
    var request = base.Request("search");

    request.AddParameter("q", searchTerm);
    request.AddParameter("count", count);

    return base.Client.ExecuteAsync<UsersResponse>(request);
}

Here's a Unit Test in the same library project's source code, that works. If I put a breakpoint at the Assert line and inspect the result, it contains an instance of List<UserResponse> with data from the Instagram API.

    [TestMethod, TestCategory("Users.Search")]
    public async Task Search()
    {
        var result = await users.Search("shiva");
        Assert.IsTrue(result.Data.Count > 0);
    }

In my ASP.Net MVC4 Application's HomeController, in the Index method that will query the instagram API and return a strong type List<Instasharp.Models.User> (which is contained in the Data property of the UserResponse object) to the corresponding View, the code is as follows. ( Note: This is per the documentation on the Github page and is supposed to work.).

   public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var userList = new List<InstaSharp.Models.User>();
            var mediaList = new List<InstaSharp.Models.Media>();
            var followingList = new List<InstaSharp.Models.User>();
            try
            {
                 var config = new InstaSharp.InstagramConfig(
                     clientId:"MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM",
                     clientSecret:"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

                 InstaSharp.Endpoints.Users users = new InstaSharp.Endpoints.Users(config);
                  var result = users.Search("shiva");
                  userList = result.Result.Data;
            }
            catch (Exception ex)
            {
                ViewBag.Message = ex.Message + "\n\n" + ex.StackTrace.ToString();
            }

            return View(userList);
        }
    }

The Problem:
My code is hanging (i.e. localhost:portnumber is just waiting.). There are no issues authenticating with Instagram API. The line

var result = users.Search("shiva");

is showing that result is a Task. I am not sure how to invoke it and get the Data in the return value from the users.Search("shiva") method.

What I have Tried:
I've tried adding the await in front of the users.Search("shiva") call. Then the compiler is asking me to make the ActionResult Index() also async and wrap a Task<..> around it. When I did that also, the code is hanging. I also tried looking on MSDN at this tutorial, but that didn't help either. I've spent quite a few hours on this, and am hoping someone on SO can help me.

[Note: This is not production code. I am simply trying to get the Instasharp library working in an ASP.Net MVC4 Controller and display data in a View. So please don't get fixated on coding practices etc. Also, I've faked out the ClientId and ClientSecret for the question. I don't think you would need it to answer this question.]

svick
  • 236,525
  • 50
  • 385
  • 514
Shiva
  • 20,575
  • 14
  • 82
  • 112

1 Answers1

3

To properly make calls to async methods in MVC4+ you should make your actions asynchronous by returning Task<ActionResult> and using await to wait for completion of the async methods.

Covered in details in following MSDN article Using Asynchronous Methods in ASP.NET MVC 4 (as well many others). Sample from article below:

public async Task<ActionResult> GizmosAsync()
{
    var gizmoService = new GizmoService();
    var result = await gizmoService.GetGizmosAsync();
    return View("Gizmos", result);
}

Note that using Wait or Result in ASP.Net will cause deadlock (as you observe). There are many questions/articles discussing it -i.e. await vs Task.Wait - Deadlock?

Community
  • 1
  • 1
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179