8

I'm having a problem with an async method that I implemented. The method basically makes a HttpRequest to a resource and deserializes the string if the request is successful. I wrote a test for the method, and it works. But the method does never return when I call it from a controller?

    public async Task<IEnumerable<T>> Get()
    {
        try
        {
            var resourceSegmentUri = new Uri(_uri, UriKind.Relative);

            var response = await _client.GetAsync(resourceSegmentUri);

            if (response.IsSuccessStatusCode)
            {
                var submission = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<IEnumerable<T>>(submission);
            }

            if (response.Content != null)
            {
                var message = response.Content.ReadAsStringAsync();
                throw new WebException(message.Result, (WebExceptionStatus)response.StatusCode);
            }

        }
        catch (WebException e)
        {
            Logger.Error("GET Request failed with status: {0}", e.Status);
            throw;
        }

        throw new Exception();
    }

Code that never returns:

public ActionResult Index()
{
   var api = new Api();
   var test = api.Get().Result; //Never returns
   return View();
}

Test that works:

[Test]
public void GetShouldReturnIfSuccessfulRequest()
{
    var api = new Api();
    var submission = api.Get();

    Console.WriteLine(JsonConvert.SerializeObject(submission));
    Assert.NotNull(submission);
}

Does anyone know the problem?

3
  • I'm not sure I understand your question. There is no return ...; statement in your Index() method, therefore it can't return anything. Commented Apr 16, 2013 at 10:56
  • Sorry missed the return statement, but it's inrelevant really. Commented Apr 16, 2013 at 11:01
  • Change your test so that is gets the result of the async method otherwise you're not testing what you intended. api.Get() should probably be api.Get().Result Commented Apr 16, 2013 at 11:23

1 Answer 1

12

You've got a deadlock because you're calling .Result in your controller action.

If you use async/await then you have to use asynchronous actions too.

So something like this should fix it:

public async Task<ActionResult> Index()
{
  var api = new Api();
  var test = await api.Get(); // Should return
}

There's a comprehensive article about this here: Using Asynchronous Methods in ASP.NET MVC 4

Sign up to request clarification or add additional context in comments.

7 Comments

Does not work. I have tried it. Basically in my real solution I wrap the Get() method in a service method that returns a model to the controller.
@BjBlazkowicz Then the best option would be to make the service method async too. If you start using async/await you have to use it all the way up the call stack.
I have made the service method async, still does not work. The thing is that I wrote a test for it in NUnit and it works fine. But the method never returns when calling it from a controller.
@BjBlazkowicz Just saw your edit - in your test, submission will be the Task not the result, so it's not really testing your method.
+1. @BjBlazkowicz: I explain the cause of the deadlock on my blog and in my recent MSDN article.
|

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.