Search code examples
c#xamarinxamarin.formshttpclient

HttpClient in Xamarin.Forms throwing "An error occurred while sending the request."


I use Xamarin.Forms to develop a multiplateform app on Windows(UWP) and Android. Also I use a WebService from an ERP running on the LAN of the Enterprise I work. This WebService is available in a normal request in C# with WebRequest and it works fine. But Xamarin prefers, with several plateforms, to use HttpClient with asynchronous methods. The WebRequest indeed doesn't work with android, and it locks the UI in UWP.

So I created a RestService like its in MSDN and no way to make the request responding. Just if I put the request with WebRequest just before the request with HttpClient, it works and I receive the XML like I want.

If I put only the HttpClient Request it throws a simple error → HttpRequestException with just ("An error occurred while sending the request."). The InnerException is → "The text associated with this error code cannot be found. The certification authority is not valid or correct."

The goal is multiplatform so HttpClient is required I think, I've already tried to put certificates validations and searched on many forums without finding the answer!!

Hope Somebody can help me!

Request working with WebRequest

public string Request(string uri)
{
     string responseFromServer = "";
     ServicePointManager.ServerCertificateValidationCallback = delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };

     WebRequest request = WebRequest.Create(uri);
     request.Credentials = new NetworkCredential(user, pswd);
     request.Method = "GET";

     HttpWebResponse response = (HttpWebResponse)request.GetResponse();

     if (((HttpWebResponse)response).StatusDescription == "OK")
     {
          Stream dataStream;
          using (dataStream = response.GetResponseStream())
          {
               StreamReader reader = new StreamReader(dataStream);
               responseFromServer = reader.ReadToEnd();
          }
     }
     response.Close();

     return responseFromServer;
}

My request with HttpClient

//Constructor 
public RestService()
{
     //Authentification for the request header
     user = "**";
     pswd = "*****";
     society= "*****";
     user = "%CP1252%" + Base64Encode(user + "@@" + society+ "@@00000");
     pswd = Base64Encode(pswd );
     var authData = string.Format("{0}{1}", user, mdp);

     client = new HttpClient();
     client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authData);

     //Security protocol
     ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
     ServicePointManager.ServerCertificateValidationCallback = delegate (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { return true; };
}

//Request method
public async Task<string> GetDatas(string url)
{
     Uri uri = new Uri(string.Format(url, string.Empty));
     string content = "";

     try
     {
          HttpResponseMessage response = await client.GetAsync(uri);
          response.EnsureSuccessStatusCode();
          content = await response.Content.ReadAsStringAsync();
     }
     catch (HttpRequestException e)
     {
          Console.WriteLine(e.Message);
     }
     return content;
}

Where I do my request in the MockDataStore to fill a list of objects

public async Task<IEnumerable<Operation>> GetItemsAsync(bool forceRefresh = false)
{
     GetOperations(); // call WebRequest Method

     await GetOperationsAsync(); // call HttpClient Method

     return await Task.FromResult(Operations);
}

Attempt to custom default headers of httpclient instance with GetStringAsync

client = new HttpClient();

client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authData);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("Mozilla", "5.0"));
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("AppleWebKit", "537.36"));
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("Chrome", "91.0.4472.114"));
client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("Safari", "537.36"));
client.DefaultRequestHeaders.Host = "srverp:****";
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("br"));
client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("fr-FR"));
client.DefaultRequestHeaders.Connection.Add("keep-alive");
client.DefaultRequestHeaders.Pragma.Add(new NameValueHeaderValue("no-cache"));

Attempt to custom headers of the request using sendAsync

var request = new HttpRequestMessage()
{
     RequestUri = uri,
     Method = HttpMethod.Get,
     Headers = {
          { HttpRequestHeader.Authorization.ToString(), "Basic " + authData},
          { HttpRequestHeader.Accept.ToString(), "application/xml" }
     },
};

var task = client.SendAsync(request).ContinueWith((taskwithmsg) =>
{
     var response = taskwithmsg.Result;
     var tmp = response.Content.ReadAsStringAsync();
     content = tmp.Result;
});
task.Wait();

Solution

  • Problem solved by adding the header of the httpClient in a Handler instance like this :

    public HttpClient HttpclientAccount
    {
         get
         {
              client = client ?? new HttpClient
              (
                   new HttpClientHandler()
                   {
                        ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
                        {
                             //bypass
                             return true;
                        },
                   }
                   , false
              );
    
              // authentification headers
              client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", 
    Convert.ToBase64String(Encoding.UTF8.GetBytes($"{user}:{mdp}")));
              return client;
         }
    }
    

    Using this method, the authentification works and the response is good!