Forum General

Need a help for httpclient in PCL

vit_chenvit_chen CNMember
edited December 2016 in General

When I use Httpclient to connect to the sever in LAN it works fine. But when connecting to the server in the Internet. It will be timed out after the first request. It's so strange that it works fine in the first request, And I also find that when make the HttpClient object static, it also works, but it cannot reconnect to server again when server have closed the conection. Can anyone help me, thanks very much!
`public partial class List : ContentPage
{
btnReload.Command = new Command(async () =>
{
await BindSearchResult();
});

    private async Task<bool> BindSearchResult()
    {
        try
        {
            var mpContent = new MultipartFormDataContent();
            mpContent.Add(new StringContent(this.PageIndex.ToString(), Encoding.UTF8), "pageIndex");
            mpContent.Add(new StringContent(this.PageSize.ToString(), Encoding.UTF8), "pageSize");
            var postResult = await PostAsync<SearchResult>("myurl", mpContent);
            if (postResult != null && postResult.success)
            {
                if (postResult.data.total > 0)
                {
                }
            }
        }
    }

    private async Task<T> PostAsync<T>(string url, MultipartFormDataContent paraContent, Action<string> callback = null)
    {
        using (var client = new HttpClient(new NativeMessageHandler()))
        {
            var cts = new CancellationTokenSource();
            client.Timeout = TimeSpan.FromSeconds(8);
            try
            {
                var response = await client.PostAsync(new Uri(url), paraContent);
                if (response.IsSuccessStatusCode)
                {
                    var result = JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result);
                    return result;
                }
            }
            catch (WebException e)
            {
                if (e.Status == WebExceptionStatus.ConnectFailure)
                {
                    callback("check network please!");
                }
            }
            catch (TaskCanceledException e)
            {
                if (e.CancellationToken == cts.Token)
                {
                    //canceled by user
                }
                else
                {
                    callback("timeout");
                }
            }
            catch (Exception e)
            {
                callback(e.Message);
            }
            return default(T);
        }
    }

}
`

Tagged:

Answers

  • NMackayNMackay GBInsider, University mod
    edited December 2016

    @vit_chen

    I have a similar static class with various restful helpers with no such issues, I have read that wrapping the HttpClient in a using statement can cause issues.

     public static class RestServiceCall<T>
     {
    
     public static async Task<List<T>> PostFetchList(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)
                {
                    switch (response.StatusCode)
                    {
                        case HttpStatusCode.Unauthorized:
                            throw new SecurityException(WebConstants.ServiceSecWarning, new Exception(response.Content.ToString()));
                        case HttpStatusCode.BadGateway:
                        case HttpStatusCode.ServiceUnavailable:
                            throw new WebException(WebConstants.ServiceUnavailable);
                    }
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        throw new WebException(WebConstants.ServiceFault);
                    }
                }
    
                return JsonConvert.DeserializeObject<List<T>>(await response.Content.ReadAsStringAsync());
            }
    
    
     public static async Task<T> PostFetchObject(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)
                {
                    switch (response.StatusCode)
                    {
                        case HttpStatusCode.Unauthorized:
                            throw new SecurityException(WebConstants.ServiceSecWarning, new Exception(response.Content.ToString()));
                        case HttpStatusCode.BadGateway:
                        case HttpStatusCode.ServiceUnavailable:
                            throw new WebException(WebConstants.ServiceUnavailable, new Exception(response.Content.ToString()));
                    }
                    if (response.StatusCode != HttpStatusCode.OK)
                    {
                        throw new WebException(WebConstants.ServiceFault);
                    }
                }
    
                var jsonContent = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<T>(jsonContent);
            }
    }
    

    This obviously never gets called unless there device thinks it's connected to WiFi and a mobile data connection although due to a bug in mono that is not always the case (known issue).

  • kentuckerkentucker USMember ✭✭✭✭✭

    Looking at your code I noticed BindSearchResult never returns anything. I do not think your await will ever finish if you dont return something.

  • vit_chenvit_chen CNMember

    @NMackay Thank you for your reply. I try many ways to post include doing without using statement. But none works. And I've found in the Output window of vs that
    _wapi_connect: error looking up socket handle 0x1d
    This may be the reason why this issue occurred in my opinion. Any more ideas.

  • vit_chenvit_chen CNMember

    @kentucker Thank you for your reply. It still have this issue even though I Set BindSearchResult returns. So I think it's not the point. Any more suggestions.

  • vit_chenvit_chen CNMember
    edited December 2016

    And I try request in a simpler demo. It still have this issue
    using System; using System.Net.Http; using System.Text; using Xamarin.Forms; namespace AppPortable { public partial class TestPage : ContentPage { public TestPage() { InitializeComponent(); btnTest.Command = new Command(async () => { var mpContent = new MultipartFormDataContent(); mpContent.Add(new StringContent("0", Encoding.UTF8), "pageIndex"); mpContent.Add(new StringContent("10", Encoding.UTF8), "pageSize"); using (var client = new HttpClient()) { client.Timeout = TimeSpan.FromSeconds(8); client.CancelPendingRequests(); try { var response = await client.PostAsync(new Uri("myUrl"), mpContent); if (response.IsSuccessStatusCode) { DisplayAlert("xx", "success", "ok"); } } catch (Exception e) { DisplayAlert("xx", "fail", "ok"); } } }); } } }
    It almost drive me crazy... And I don't think it's due to the async pattern, because I have tried it in sync pattern, the same result.

Sign In or Register to comment.