HttpClient GetAsync never returns

I have a button thats hooked up with a Command in ViewModel as following:

public string VINNumber {get; set;}
public string API_KEY {get; set;}
Command _DecodeVINCommand;
public Command DecodeVINCommand {
    get { return _DecodeVINCommand ?? (_DecodeVINCommand = new Command( ()=> { ExecuteDecodeVINCommand(); })); }
}
private async Task ExecuteDecodeVINCommand() {
    using (HttpClient client = new HttpClient())
    {
        client.BaseAddress = new Uri("https://api.edmunds.com/api/");
        var response = await client.GetAsync("vehicle/v2/vins/" + VINNumber + "?fmt=json&api_key="+API_KEY);
        if (response.IsSuccessStatusCode)
        {
            var str = await response.Content.ReadAsStringAsync();
            var temp = JsonConvert.DeserializeObject(str);
        }
    }
}

This doesnt work for some reason, as it never returns to response.IsSuccessStatusCode. I use the exact same thing in another Windows Form test project and also postman and in both scenarios, it works fine.

Could someone help?

Answers

  • JohnMillerJohnMiller USForum Administrator, Xamarin Team Xamurai

    @VictorNguyen1902,

    Set your debugger to break on any exception to make sure that there isn't something being missed.

  • @John: I put my codes above inside a try catch block and didnt get any exception. Somewhere else in my app I also made a call to google map API and didnt have this kinda issue. With that being said, I tried using the following url for the above codes and surprisingly everything seems to work fine again

    https://maps.googleapis.com/maps/api/directions/xml?origin=Disneyland&destination=Universal+Studios+Hollywood4
    

    I also already tried the above code in my API server and it doesnt have any problem. So maybe the work around for now is just to go through the API server.

  • JohnMillerJohnMiller USForum Administrator, Xamarin Team Xamurai

    @VictorNguyen1902,

    I am not convinced that the try/catch would work given the async call. The calling method is not async/await so I thought maybe it was being swallowed.

    Set the debugger to break on any exception and see if you get any results.

    ()=> { ExecuteDecodeVINCommand();
    

    This is where I think the exception would be lost.

  • VictorNguyen1902VictorNguyen1902 USMember ✭✭
    edited November 2016

    @John: I think I found where my problem is. Apparently it did return but not to the break point I set, which is right at the line

    if (response.IsSuccessStatusCode) // it stepped over this for some reason
    

    I didnt have any break point after this line, so I was assuming it didnt go back here. I set another one at

    var temp = JsonConvert.DeserializeObject(str);
    

    and it seems to be working now.

    I'm kinda confused actually, because in other projects, I was redirected back to the StatusCode check break point, but not in this one particularly. I'm tesing my app on iPhone 6s simulator via VS2015.

  • ThomasBurkhartThomasBurkhart DEMember ✭✭✭✭
    edited November 2016

    No, try catch should work aroung async calls, that should not be the problem

    But shouldn't you use an async lambda?

  • @ThomasBurkhart: until now I'm still not sure if using one over the other is going to make any difference in my code, since there's nothing to be followed up after ExecuteDecodeVINCommand. I guess thats why I was just sticking with what's been being used in our team.

  • MaxMengMaxMeng NZMember ✭✭✭

    new Command( ()=> { ExecuteDecodeVINCommand(); }));

    Shouldn't this be:

    new Command( async ()=> { await ExecuteDecodeVINCommand(); })); ?

  • ThreezoolThreezool USMember ✭✭
    edited November 2016

    I had the same issue when i migrated my old code over to Forms, this is how i solved it:

    Replace
    var response = await client.GetAsync(url);

    With
    var requestTask = client.GetAsync(url); var response = Task.Run(() => requestTask);

    Dont know why it woked before migrating but not now but that did it for me.

  • NMackayNMackay GBInsider, University mod

    @Threezool

    Doing a Task.Run() on restful calls is an overhead as it is spinning up a new thread for each call, I've never had to do that for any HTTPClient call but we use Posts generally and not Get so I couldn't say if that's always the case but using Task.Run will have a performance impact.

            public static async Task<string> PostFetchString(string url, object toPost, CancellationToken ct,
                Dictionary<string, string> headers = null)
            {
                var httpClient = new HttpClient();
                HttpContent content = new StringContent(JsonConvert.SerializeObject(toPost), Encoding.UTF8,
                    WebConstants.ContentTypeJson);
    
                if (!Equals(headers, null))
                {
                    foreach (var header in headers)
                    {
                        content.Headers.Add(header.Key, header.Value);
                    }
                }
    
                var response = await httpClient.PostAsync(new Uri(url), content, ct);
    
                if (!response.IsSuccessStatusCode)
    
  • CodySigvartsonCodySigvartson USMember ✭✭

    @NMackay I know this is an old post but I have been stuck on trying to get this to work for a while now. I have very similar code to what you posted there but when I debug it just gets stuck on the second to last line "var response = await ..." it's like the call never returns. It never goes into my catch block it just stops. Any thoughts?

  • NMackayNMackay GBInsider, University mod

    @CodySigvartson

    It's hard to say, how are you calling it? is the code calling the function been awaited ?

  • CodySigvartsonCodySigvartson USMember ✭✭

    Here is my function def:
    public async Task PostData(PostData data)
    {
    try
    {
    var uri = new Uri("http://localhost:59915/my_service.svc/UploadReport");
    var json = JsonConvert.SerializeObject(data);
    var content = new StringContent(json, Encoding.UTF8, "application/json");

                HttpResponseMessage response = null;
    
                response = await client.PostAsync(uri, content);
                if (response.IsSuccessStatusCode)
                {
                    Debug.WriteLine("Successful POST");
                }
            }
            catch(Exception ex)
            {
                Debug.WriteLine(ex);
            }
        }
    

    Here is where I am making the call to the above function:
    async void OnButtonClicked(object sender, EventArgs e)
    {
    PostData data = new PostData()
    {
    // my data is being initialized properly here
    };
    RestService service = new RestService();
    await service.PostData(data);
    }

  • CodySigvartsonCodySigvartson USMember ✭✭

    @N_Baua Well, I figured out my issue. Since I am running this on an Android tablet that is not on the same network as my localhost duh it wouldn't work. I instead am using an azure endpoint and just have my android tablet connected to wifi and WALA it works. Duh. With that being said, do you know how I can run this on my Android tablet while using localhost instead of something like Azure hosting? Thanks for your help.

  • NMackayNMackay GBInsider, University mod

    Maybe check if the task is returning a result.

    ves res = await service.PostData(data);
    //do something here and put a breakpoint in to see what if the task faults etc
    

    It's hard to diagnose code like that

  • N_BauaN_Baua INMember ✭✭✭✭✭

    @CodySigvartson said:
    @N_Baua Well, I figured out my issue. Since I am running this on an Android tablet that is not on the same network as my localhost duh it wouldn't work. I instead am using an azure endpoint and just have my android tablet connected to wifi and WALA it works. Duh. With that being said, do you know how I can run this on my Android tablet while using localhost instead of something like Azure hosting? Thanks for your help.

    Well the network endpoints must communicate. I can say affirmatively localhost solutions are a pure no go.
    At least try to host service on your local IIS server and access it by a network ip address like 192.168.1.120 or something.

    Also as Norman Mackey suggests, at least debug once on the result returned by service.

    Post your findings here, unless it will be difficult to answer.

    • N Baua
  • CodySigvartsonCodySigvartson USMember ✭✭

    @NMackay @N_Baua Thank you both for your help. N_Baua as you can see I am working on multiple applications at once with the same problem haha. Anyways, when I was debugging trying to see my response nothing would ever return from the service so I was never able to check what the response was. It would essentially just stop after that call and the application would sit there with no crash or anything so I am assuming it just kept trying to reach the endpoint and had I waited long enough would most likely timeout. Thanks for the tip on using IP address to access local host I will try that out. All in all, I have both of my applications working and I am moving on from this issue for now. Thanks to you both.

  • AlanStrattonAlanStratton USMember ✭✭

    I was able to work around this problem in this manner:

    1) Install IIS on my local machine, and deploy my WebAPI project to that.
    2) Change my Url I use for connecting to the WebAPI from localhost to the hostname of my machine
    3) Ensured that the Android Permissions allowed "INTERNET"

    The Virtual Machine for the Android emulator needs something different than localhost due to the way it is networked.

  • SteveRussellSteveRussell Member ✭✭

    I have a similar problem. I'm using Xamarin.Forms.Maps and when a user searches for a zipcode, it sometimes doesn't return what it should.

    `try
    {
    var isNumeric = int.TryParse(MapSearchIDText, out int n);
    if (isNumeric)
    {
    request = string.Format("https://maps.googleapis.com/maps/api/geocode/xml?components=country:DK|postal_code:{0}&key={1}", Uri.EscapeUriString(MapSearchIDText), GooglePlacesApiKey);
    }
    else
    {
    request = string.Format("https://maps.googleapis.com/maps/api/geocode/xml?address={0}&region=DK&key={1}", Uri.EscapeUriString(MapSearchIDText), GooglePlacesApiKey);
    }
    var xml = await (new HttpClient()).GetStringAsync(request);
    var result = XDocument.Parse(xml).Element("GeocodeResponse").Element("result");
    var loc = result.Element("geometry").Element("location");
    var SearchLat = double.Parse(loc.Element("lat").Value.ToString(), CultureInfo.InvariantCulture);
    var SearchLong = double.Parse(loc.Element("lng").Value.ToString(), CultureInfo.InvariantCulture);

          if (result.Element("type").Value.ToString().Contains("locality") || result.Element("type").Value.ToString().Contains("postal_code"))
          {
            PSMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(SearchLat, SearchLong), Distance.FromKilometers(8)));
          }
          else
          {
            PSMap.MoveToRegion(MapSpan.FromCenterAndRadius(new Position(SearchLat, SearchLong), Distance.FromKilometers(0.2)));
          }
        }
    

    catch
    {
    await DisplayAlert("Address does not exist", "Please try again", "OK");
    }`

    When I search for, for example '8000' it works, and centers to the corresponding city. But when I type in '2000' on search, I get the display alert. When I copy the exact string from 'request' and put it onto my browser, I do get the correct result.

    After debugging I notice that in

          var xml = await (new HttpClient()).GetStringAsync(request);
    

    It says that the expression is not supported, and result is then null.

Sign In or Register to comment.