How to use async Task to get data and show in a view?

Viewed 3628

I have a web API and i want to get some data in a controller and show on a view.

this is my main class:

public class APISrv
{
   public string result = string.Empty;
    public async Task<string> GetIT()
    {
        try
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://localhost:2474/");
                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Accept.Add(new 
                 MediaTypeWithQualityHeaderValue("application/json"));

                HttpResponseMessage Res = await 
                client.GetAsync("api/Test/Get");

                if (Res.IsSuccessStatusCode)
                {
                    result = Res.Content.ReadAsStringAsync().Result;
                }
            }

        }
        catch (Exception err)
        {
            result=err.Message;
        }
        return result;
    }
}

i tested my class with two controllers:

one:

public ActionResult Index()
    {
        APISrv aPISrv = new APISrv();
        aPISrv.GetIT();
        ViewData["mydata"] = aPISrv.result;
        return View();
    }

in this cause "result" is a public field and always is empty,it seems main thread does not wait for async method done its work.i can see my view but "ViewData["mydata"]" is empty.

on second:

public ActionResult Index()
    {
        APISrv aPISrv = new APISrv();
        ViewData["mydata"] = aPISrv.GetIT().Result;
        return View();
    }

in this cause my page stay in "waiting for local..." mode and does not work anything.

how can i and what is the best way to get data from my class?

1 Answers

You are mixing Blocking calls (.Result) with async/await, which can lead to deadlocks. That is what you are not getting back results when you call the controller action.

Reference Async/Await - Best Practices in Asynchronous Programming

Either go async all the way or synchronous all the way. Try not to mix them.

result = await Res.Content.ReadAsStringAsync();

Also update the action to be async as well

public async Task<ActionResult> Index() {
    var aPISrv = new APISrv();
    ViewData["mydata"] = await aPISrv.GetIT();
    return View();
}

Additionally that service should be abstracted out and injected via constructor injection, but that is outside of the scope of this question.

Related