Marius
Marius

Reputation: 58911

Any reason to use async/await when the controller action is sync?

Lets say I have a controller action that cannot be made async (for various reasons), but I have a service that (through several methods) calls a rest service using HttpClient. Is there any thing to gain by using the async client and using .Wait or .Result? Or would it be less performant to use the synchronous method?

So either:

//MyController.cs
public ActionResult GetSomething(int id)
{
    //lots of stuff here
    var processedResponse = _myService.Get(id);
    //lots more stuff here
    return new ContentResult(result);
}

//MyService.cs
public ProcessedResponse Get(int id)
{
    var client = new HttpClient();
    var result = client.Get(_url+id);
    return Process(result);
}

Or:

//MyController.cs
public ActionResult GetSomething(int id)
{
    //lots of stuff here
    var processedResponse = _myService.GetAsync(id).Result;
    //or, .Wait, or Task.Run(...), or something similar
    //lots more stuff here
    return new ContentResult(result);
}

//MyService.cs
public async Task<ProcessedResponse> GetAsync(int id)
{
    var client = new HttpClient();
    var result = await client.GetAsync(_url+id);
    return await Process(result);
}

Upvotes: 2

Views: 2066

Answers (3)

Batavia
Batavia

Reputation: 2497

It gets interesting when do can do it like this

//MyController.cs
public ActionResult GetSomething(int id)
{
    var processedResponseTask = _myService.GetAsyn(id)
    //lots of stuff here (1)

    var processedResponseTask.Wait();
    var processedResponse = processedResponseTask.Result;

    //lots more stuff here (2)
    return new ContentResult(result);
}

now the lots of stuff here(1) is done in parallel with your async task. (Or if you called your service twice for example). If you don't actually do a lot around lots of stuff here(1) then there isn't much of a point.

Upvotes: 0

Amit
Amit

Reputation: 46323

In your scenario, no there isn't a good reason, but lets add some functionality:

//MyController.cs
public ActionResult GetSomething(int id)
{
    //lots of stuff here
    var processedResponse = _myService.GetAsync(id).Result;
    //or, .Wait, or Task.Run(...), or something similar
    //lots more stuff here
    return new ContentResult(result);
}

//MyService.cs
public async Task<ProcessedResponse> GetAsync(int id)
{
    var client = new HttpClient();
    var pendingResult1 = client.GetAsync(_url+id);
    var pendingResult2 = someAsyncOperation();
    var result3 = someSyncOperation();
    var result1 = await pendingResult;
    var result2 = await pendingResult2;
    return await Process(result1, result2, result3);
}

Now, since your request takes a while to complete, someAsynchOperation starts executing immediately instead of waiting for GetAsync() to complete. someSyncOperation is also being executed in the meantime.

Without the async keyword, you would not be able to use await, so it's better to have it if you plan to have asynchronous execution inside your funciton.

Upvotes: 2

Yuval Itzchakov
Yuval Itzchakov

Reputation: 149518

Is there any thing to gain by using the async client and wrapping the method in Task.Run(() => _myService.Get()).Result?

The only thing you'll most likely end up gaining is a deadlock. Think about it, you're queuing a naturally asynchronous method on a thread-pool thread, where the ASP.NET already gave you a thread to process you Action inside. There isn't much sense in that.

If you want to go async, and think you'll actually benefit from the scale provided by asynchrony, then you should re-factor your controllers to be async as well and return a Task<T>, where you can await those asynchronous methods.

So I'd either stay synchronous, or re-factor the code top to bottom to support async:

//MyController.cs
public async Task<ActionResult> GetSomethingAsync(int id)
{
    //lots of stuff here
    await GetAsync(id);
    return new ContentResult(result);
}

//MyService.cs
public async Task<ProcessedResponse> GetAsync(int id)
{
    var client = new HttpClient();
    var result = await client.GetAsync(_url+id);
    return await Process(result);
}

Upvotes: 5

Related Questions