By user11287929


2019-06-12 05:44:26 8 Comments

I want to make a proper HTTPClient request. I have a code but I am always getting so may exceptions like:

  1. Java.IO.IOException: Socket closed
  2. System.OperationCanceledException: The operation was canceled.
  3. Java.Net.SocketException: Connection reset
  4. Java.Net.SocketException: Software caused connection abort
  5. Java.Net.UnknownHostException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
  6. Java.Net.UnknownHostException: Unable to resolve host "tbs.scratchit.ph": No address associated with hostname
  7. Java.IO.IOException: isConnected failed: ETIMEDOUT (Connection timed out)
  8. Java.Net.SocketException: recvfrom failed: ECONNRESET (Connection reset by peer)

I am always getting these kinds of exceptions, errors.

I am starting to wonder how can I create a Post Async and GetAsync properly to avoid these errors in the future?

Here is how I create a HTTP Client:
1. I have a class call Constants, in there I will declare a new HTTP Client so that I only have 1 HTTPClient across my project

public class Constants
{
    public static HttpClient client = new HttpClient();
}

2. I have a function(s) that gets data from my server through a PHP API by sending the parameters through JSON.

public async void FirstTimeSyncUser(string host, string database, string contact, string ipaddress)
    {
        try
        {
            syncStatus.Text = "Checking internet connection";

            string apifile = "first-time-sync-user-api.php";

            if (CrossConnectivity.Current.IsConnected)
            {
                syncStatus.Text = "Initializing first-time user sync";

                var db = DependencyService.Get<ISQLiteDB>();
                var conn = db.GetConnection();

                var getData = conn.QueryAsync<UserTable>("SELECT * FROM tblUser WHERE ContactID = ? AND Deleted != '1'", contact);
                var resultCount = getData.Result.Count;

                var current_datetime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                int count = 1;

                var settings = new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore,
                    MissingMemberHandling = MissingMemberHandling.Ignore
                };

                if (resultCount == 0)
                {
                    syncStatus.Text = "Getting user data from the server";

                    var link = "http://" + ipaddress + "/" + Constants.apifolder + "/api/" + apifile;
                    string contentType = "application/json";
                    JObject json = new JObject
                    {
                        { "Host", host },
                        { "Database", database },
                        { "ContactID", contact }
                    };

                     Constants.client.DefaultRequestHeaders.ConnectionClose = true;

                    var response = await Constants.client.PostAsync(link, new StringContent(json.ToString(), Encoding.UTF8, contentType));

                    if (response.IsSuccessStatusCode)
                    {
                        var content = await response.Content.ReadAsStringAsync();

                        if (!string.IsNullOrEmpty(content))
                        {
                            try
                            {
                                var dataresult = JsonConvert.DeserializeObject<List<UserData>>(content, settings);
                                var datacount = dataresult.Count;

                                for (int i = 0; i < datacount; i++)
                                {
                                    syncStatus.Text = "Syncing user " + count + " out of " + datacount;

                                    var item = dataresult[i];
                                    var userid = item.UserID;
                                    var usrpassword = item.UsrPassword;
                                    var usertypeid = item.UserTypeID;
                                    var userstatus = item.UserStatus;
                                    var lastsync = DateTime.Parse(current_datetime);
                                    var lastupdated = item.LastUpdated;
                                    var deleted = item.Deleted;

                                    var insertdata = new UserTable
                                    {
                                        UserID = userid,
                                        UsrPassword = usrpassword,
                                        ContactID = contact,
                                        UserTypeID = usertypeid,
                                        UserStatus = userstatus,
                                        LastSync = lastsync,
                                        LastUpdated = lastupdated,
                                        Deleted = deleted
                                    };

                                    await conn.InsertOrReplaceAsync(insertdata);

                                    count++;
                                }

                                synccount += "Total synced user: " + count + "\n";

                                var logType = "App Log";
                                var log = "Initialized first-time sync (<b>User</b>)  <br/>" + "App Version: <b>" + Constants.appversion + "</b><br/> Device ID: <b>" + Constants.deviceID + "</b>";
                                int logdeleted = 0;

                                Save_Logs(contact, logType, log, database, logdeleted);

                                Preferences.Set("userchangeslastcheck", current_datetime, "private_prefs");

                                FirstTimeSyncSystemSerial(host, database, contact, ipaddress);
                            }
                            catch
                            {
                                var retry = await DisplayAlert("Application Error", "Syncing failed. Failed to send the data.\n\n Error:\n\n" + content + "\n\n Do you want to retry?", "Yes", "No");

                                if (retry.Equals(true))
                                {
                                    FirstTimeSyncUser(host, database, contact, ipaddress);
                                }
                                else
                                {
                                    First_Time_OnSyncFailed();
                                }
                            }
                        }
                        else
                        {
                            Preferences.Set("userchangeslastcheck", current_datetime, "private_prefs");

                            FirstTimeSyncSystemSerial(host, database, contact, ipaddress);
                        }
                    }
                    else
                    {
                        var retry = await DisplayAlert("Application Error", "Syncing failed. Server is unreachable.\n\n Error:\n\n"+ response.StatusCode +" Do you want to retry?", "Yes", "No");

                        if (retry.Equals(true))
                        {
                            FirstTimeSyncUser(host, database, contact, ipaddress);
                        }
                        else
                        {
                            First_Time_OnSyncFailed();
                        }
                    }
                }
                else
                {
                    SyncUserClientUpdate(host, database, contact, ipaddress);
                }
            }
            else
            {
                var retry = await DisplayAlert("Application Error", "Syncing failed. Please connect to the internet to sync your data. Do you want to retry?", "Yes", "No");

                if (retry.Equals(true))
                {
                    FirstTimeSyncUser(host, database, contact, ipaddress);
                }
                else
                {
                    First_Time_OnSyncFailed();
                }
            }
        }
        catch (Exception ex)
        {
            Crashes.TrackError(ex);
            var retry = await DisplayAlert("Application Error", "Syncing failed. Failed to send the data.\n\n Error:\n\n" + ex.Message.ToString() + "\n\n Do you want to retry?", "Yes", "No");

            if (retry.Equals(true))
            {
                FirstTimeSyncUser(host, database, contact, ipaddress);
            }
            else
            {
                First_Time_OnSyncFailed();
            }
        }
    }

3. After getting the data I needed it will execute another function with another POSTASYNC Call. In my code above when I got the user data from my server it will execute the next function which is FirstTimeSyncSystemSerial(host, database, contact, ipaddress);

What am I doing wrong? and How can I improve this so that I can avoid these exceptions?

2 comments

@Ishara Lakshitha 2019-06-12 07:43:21

You can Make a Generic Custom Service call That Can be Called Anywhere When You Need

 public class RestClient : IRestClient
{
    private const string TokenHeaderKey = "Any Token Header";
    private HttpClient _httpclient = new HttpClient();

    public async Task<T> GetAsync<T>(string url, string token) where T : new()
    {
        var responseContent = await ExecuteRequest(
            async () =>
            {
                try
                {
                    AddTokenToDefaultRequestsHeader(token);
                    return await _httpclient.GetAsync(url);
                }
                finally
                {
                    ClearAuthenticationHeader();
                }
            });

        return await Deserialize<T>(responseContent);
    }

    private void AddTokenToDefaultRequestsHeader(string token)
    {
        _httpclient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(TokenHeaderKey, token);
    }

    private void ClearAuthenticationHeader()
    {
        _httpclient.DefaultRequestHeaders.Authorization = null;
    }

    private static async Task<HttpContent> ExecuteRequest(Func<Task<HttpResponseMessage>> requestFunc)
    {
        HttpResponseMessage response = null;
        try
        {
            response = await requestFunc();
            if (!response.IsSuccessStatusCode)
            {
                var message = $"Executed HTTP request returned status code {response.StatusCode} and reason phrase {response.ReasonPhrase}";

                if (response.StatusCode == HttpStatusCode.Unauthorized)
                {
                    throw new Exception(message);
                }

                throw new Exception(message);
            }

            return response.Content;
        }
        catch (Exception exception)
        {
            if (exception is HttpRequestException || exception is WebException || exception is TaskCanceledException)
            {
                throw new Exception(
                    "Could not connect to service.");
            }

            throw;
        }
    }

    private static async Task<T> Deserialize<T>(HttpContent responseContent) where T : new()
    {
        try
        {
            var responseContentString = await responseContent.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<T>(responseContentString);
        }

        catch (Exception exception)
        {
            if (exception is TaskCanceledException || exception is JsonException)
            {
                throw new Exception("Could not deserialize response content.", exception);
            }
            throw;
        }
    }

And Add an App settings class

 public class AppSettings : IAppSettings
{
    public string Server => "server url";
    public string ServerEndPoint => "End point";

    public string Token => "Token If you Have any";
}

Then Call Like this

 public class Servicecall 
{
    private readonly IRestClient _restClient;
    private readonly IAppSettings _appSettings;

    public PatientService(IRestClient restClient, IAppSettings appSettings)
    {
        _restClient = restClient;
        _appSettings = appSettings;
    }

    public async Task<IList<PatientViewModel>> GetPatients()
    {
        var url = _appSettings.Server + _appSettings.EndPoint ;
        var token = _appSettings.Token;
        return GetPatientList(await _restClient.GetAsync<List<ListModelClass>>(url, token));
    }

    public IList<Model> GetPatientList(IList<ListModelClass> List)
    {
        return List.Select(p => new Model(p)).ToList();
    }
}

This way You can Call deferent services without typing a lot of boilercodes This way You can Call Services with real ease

@user11287929 2019-06-12 08:01:10

Can you pattern that to my code? So that I can get the gist of it

@Ishara Lakshitha 2019-06-12 08:14:48

I will show it in demo project

@Ishara Lakshitha 2019-06-13 04:30:46

Is this help you

@Thinh 2019-06-12 07:33:36

Debug your code to find out where the exception is thrown. Put a try catch blocked around that block of code. Then catch all the expected exceptions and try loopback again for a number of time.

@Digitalsa1nt 2019-06-12 08:24:33

If you know you're getting errors that can likely be fixed then using a try catch instead of fixing the problem is not a suitable answer. It's just 'covering up' the problem.

Related Questions

Sponsored Content

1 Answered Questions

[SOLVED] Xamarin Forms execution returns from await Httpclient PostAsync

1 Answered Questions

[SOLVED] Xamarin Forms Httpclient PostAsync returns null

4 Answered Questions

[SOLVED] HttpClient PostAsync does not return

2 Answered Questions

[SOLVED] HttpClient PostAsync() not working

0 Answered Questions

Xamarin.ios: HttpClient GetAsync & PostAsync does not respond when network is disconnected

0 Answered Questions

1 Answered Questions

[SOLVED] Xamarin Forms HttpClient GetAsync Fails in iOS Only

1 Answered Questions

[SOLVED] Xamarin Android HttpClient PostAsync

1 Answered Questions

[SOLVED] Xamarin Forms HttpClient GetAsync

2 Answered Questions

[SOLVED] HttpClient PostAsync on xamarin does nothing

Sponsored Content