简体   繁体   中英

HttpResponseMessage Not Returning any response?

Im trying connect to a API and get the data from it. But Im not getting Anything after HttpResponseMessage code line.if (response.IsSuccessStatusCode) never runs. I have tried everything, but nothing yet. please help. This is my code.

using System;
using Newtonsoft;
using System.Net.Http.Headers; 
using System.Text; 
using System.Net.Http; 
using System.Web; 
using System.Collections.Generic;
using Newtonsoft.Json;
using System.Xml;
using System.Web.Mvc;
using System.Threading.Tasks;


namespace JKLLAppMobile.API
{
public class JKLLAPI : Controller
{
    public async Task<List<JasonData>> MakeRequest()
    {
        List<JasonData> HanaData = new List<JasonData>();

        var client = new HttpClient();
        var queryString = HttpUtility.ParseQueryString(string.Empty);
        queryString["format"] = "json";
        queryString["filter"] = "BDATU eq '20170421' and BWLVS eq '609'";
        var uri = "https://jkhapimdev.azure-api.net/api/beta/v2/bound/?" + queryString;

        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri);
        request.Headers.Authorization = new AuthenticationHeaderValue("Ocp-Apim-Subscription-Key", "{Token-Key}");
        HttpResponseMessage response = await client.SendAsync(request);

        if (response.IsSuccessStatusCode)
        {
            var responseString = await response.Content.ReadAsStringAsync();
            string json_data = JsonConvert.SerializeObject(responseString); 


        }

        return HanaData;
    }
}

}

Calling Ajax Method function TotalTestMonthly() {

    $.ajax({
        url: '../JKLLAPI/MakeRequest',
        type: 'POST',
        dataType: 'json',
        cache: false,
        async: false,
        data: {},
        success: function (data) { 
            if (data.Success == true) {

            } 
        }
    }); 
}

Since you have said it "never" runs the IsSuccessStatusCode line, not even for after a timeout, I'd guess that you have a deadlock situation happening.

As I commented above, Stephen Cleary has a really good article which describes the problem. He has also penned an MSDN article .

To summarise (in case the linked articles ever disappear):

  • When you make an async call the current SynchronizationContext (or, if it's null, the TaskScheduler) is captured as a kind of return point for the async call.
  • GUI and ASP.NET applications use SynchronizationContext. This only allows one block of synchronous code to run at once.
  • Once your async task has completed, it will try to return to the SynchronizationContext, which, if you're starting from a non-async position, will be blocked on someTask.Wait();
  • Once you reach this point, you have a situation where your synchronous code is waiting for your asynchronous code, and your asynchronous code is waiting to return to your synchronous code, causing a deadlock.

Note: According to Stephen's MSDN article, console applications do not have this issue because they use the TaskScheduler. VS' Unit Test task runner does have this issue, which is how I learned of it.


So, what can you do?

If you're running async from a GUI context, eg a button click, you should change your button click handler to an async method:

// you can't change void to Task because of the type the delegate expects,
// but this is the correct way to do this.
public async void OnClicked(...)

You can then use the standard await, and the context is handled as you would expect.

In your async methods you can call ConfigureAwait:

await Task.Delay(1000).ConfigureAwait(continueOnCapturedContext: false);
// or, simply:
await Task.Delay(1000).ConfigureAwait(false);

This causes the method to execute the rest of the async method in the Thread Pool context, which averts the deadlock.

If for some reason you can't handle, or wrap, the async method, then you can also use Task.Run :

// You can also use Task<string>.Run(...), for example
var task = Task.Run(async () => await someAsyncMethod());
task.Wait();

Using Task.Run will execute the async method within the Thread Pool context, and thus avoid the deadlock.

My explanation really doesn't do the topic justice, so I highly recommend reading the articles I linked above. I just wanted to make sure my answer contained some valuable content if the links were to ever disappear :-)

Note The correct way to do async is async all the way down (ie from the button click to the deepest async call). Task.Run shouldn't be used within an async method.


I've put together my own quick example to demonstrate these techniques:

// Deadlocks
public void button2_Click(object sender, EventArgs e)
{
    var task = GetNews();
    task.Wait();
    MessageBox.Show(task.Result);
}

// Doesn't deadlock
public async void button3_Click(object sender, EventArgs e)
{
    var result = await GetNews();
    MessageBox.Show(result);
}

// Doesn't deadlock
public void button4_Click(object sender, EventArgs e)
{
    var task = GetNews(false);
    task.Wait();
    MessageBox.Show(task.Result);
}

// Doesn't deadlock
public void button5_Click(object sender, EventArgs e)
{
    var task = Task<string>.Run(async () => await GetNews());
    task.Wait();
    MessageBox.Show(task.Result);
}

// The boolean option is just so that I don't have to write two example methods :)
// You obviously don't have to pass this as a parameter, and can just directly call ConfigureAwait
public async Task<string> GetNews(bool continueOnCapturedContext = true)
{
    await Task.Delay(100).ConfigureAwait(continueOnCapturedContext: continueOnCapturedContext);
    return "hello";
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM