1

I've been playing around with creating a REST wrapper based on https://github.com/JeffGos/urbanairsharp.

public LoginResponse Login()
    {
        return SendRequest(new LoginRequest(new Model.Login()));
    }

private static TResponse SendRequest<TResponse>(BaseRequest<TResponse> request) where TResponse : BaseResponse, new()
    {
        try
        {
            var requestTask = request.ExecuteAsync();

            return requestTask.Result;
        }
        catch (Exception e)
        {
            //Log.Error(request.GetType().FullName, e);

            return new TResponse()
            {
                Error = e.InnerException != null ? e.InnerException.Message : e.Message,
                Ok = false
            };
        }
    }

I am able to call the Login method absolutely fine from a console app but if I call it from an MVC controller, it steps through the code fine but never passes the line

var requestTask = request.ExecuteAsync();

I have read around the subject but dont quite understand how I can use these methods from a web app? The Login() method is not async so I dont see why it would fail from my MVC action (also non-async)?

Thanks

1
  • I believe this may hold your answer. Commented Oct 5, 2015 at 21:15

1 Answer 1

4

This:

var requestTask = request.ExecuteAsync();
return requestTask.Result;

Is causing your code to deadlock. You're blocking an async method synchronously with the call to Task.Result That's why you shouldn't block on async code. Instead, you need to asynchronously wait on ir with await. This will effectively make your call chain become async as well:

public Task<LoginResponse> LoginAsync()
{
    return SendRequestAsync(new LoginRequest(new Model.Login()));
}

private static async Task<TResponse> SendRequestAsync<TResponse>(BaseRequest<TResponse> request) where TResponse : BaseResponse, new()
{
    try
    {
        return await request.ExecuteAsync();
    }
    catch (Exception e)
    {
        //Log.Error(request.GetType().FullName, e);

        return new TResponse()
        {
            Error = e.InnerException != null ? e.InnerException.Message : e.Message,
            Ok = false
        };
    }
}

In case you can't change your call chain to become asynchronous, use a synchronous API instead.

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

4 Comments

ok that did the trick and I think I am understand a little more. I did read that article you mention previously but I don't quite understand why this is blocking the request. What is the point of doing it the way I previously had it?
Also, is it possible to call the LoginAsync method from a synchronous legacy VB.NET WebForm as NON async call? I tried just creating an instance of my class and calling it without Await and it seems to deadlock as before? I dont really want to start adding async everywhere to a legacy application...
@Raj No, I would definitely recommend agains't that. Async and sync methods usually have different code execution paths, and need to be "duplicated". You shouldn't do "sync over async" nor "async over sync"
@Raj Regarding your first comment, there is no advantage to executing an async method synchronously. That'll mainly lead you to cases of deadlock like you've just experienced.

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.