Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid returning type Task<Object> from an async function when using HttpClient

I am making HTTP calls using the System.Net.Http.HttpClient. It seems that all calls must be asynchronous.

Let's say I have a project structure of the following: MVC Web App -> Business Layer -> Data Layer

In the Data Layer I am making HTTP calls to a Web API to return data and I end up using a function like this:

public async Task<IList<Product>> GetProducts()
{
     HttpResponseMessage response = await client.GetAsync("api/products");
     string data = await response.Content.ReadAsStringAsync();
     IList<Product> products = JsonConvert.DeserializeObject<IList<Product>>(data);

     return products;
}

this then goes through to the BusinessLayer:

public Task<IList<Product>> GetProducts(string name = null)
{
     return _repository.GetProducts(name);
}

Then finally in the MVC controller:

public IActionResult Index()
{
    Task<IList<Product>> ProductsTask = _manager.GetProducts();

    IList<Product> ProductsNonTask = products.Result.ToList();

    return View();
}

Do I really have to make every single function return a list of type Task<IList<Product>> leading up to my MVC controller? As you can see in the MVC controller I have to retrieve the products initially with Task wrapped around them. The debugger looks kind of strange when I go to view the list of products through it. So then as you can see I convert them to a regular list of product.

I am wondering if it is the correct thing to do to have all of my functions return type Task<IList<Product>> all the way up to my MVC controller or if there is a workaround so that my functions can still return the a standard list of product but continue to use the async capabilities of the HttpClient?

UPDATE: Is there anything wrong with doing the following:

public IList<Product> GetProducts()
{
     Task<HttpResponseMessage> response = client.GetAsync("api/products");
     if (response.Result.IsSuccessStatusCode)
     {
          string data = response.Result.Content.ReadAsStringAsync().Result;
          IList<Product> products = JsonConvert.DeserializeObject<IList<Product>>(data);

          retVal = products;
     }
}
like image 544
Blake Rivell Avatar asked Jan 27 '16 21:01

Blake Rivell


People also ask

Should async method return Task?

For methods other than event handlers that don't return a value, you should return a Task instead, because an async method that returns void can't be awaited. Any caller of such a method must continue to completion without waiting for the called async method to finish.

Is HttpClient asynchronous?

This example demonstrates a basic asynchronous HTTP request / response exchange. Response content is buffered in memory for simplicity. This example demonstrates an asynchronous HTTP request / response exchange with a full content streaming.

Why you should avoid async void?

Async void methods can wreak havoc if the caller isn't expecting them to be async. When the return type is Task, the caller knows it's dealing with a future operation; when the return type is void, the caller might assume the method is complete by the time it returns.

What does HttpClient GetAsync return?

The HTTP request is sent out, and HttpClient. GetAsync returns an uncompleted Task . AsyncAwait_GetSomeDataAsync awaits the Task ; since it is not complete, AsyncAwait_GetSomeDataAsync returns an uncompleted Task . Test5Controller. Get blocks the current thread until that Task completes.


1 Answers

If you want the operation to actually be asynchronous it needs to be asynchronous all the way up.

The minute you block on a Task with Wait or Result it's no longer asynchronous.

So, no. Either use async all the way up or be don't use it at all.

I wonder... if there is a workaround so that my functions can still return the a standard list of product but continue to use the async capabilities of the HttpClient?

No, there isn't really.

You should probably just make your code asynchronous as it comes with many benefits in scalability and performance. But if you're against doing so you can use WebClient that has synchronous web operations.

like image 75
i3arnon Avatar answered Sep 26 '22 02:09

i3arnon