GetRequestStream() timeout exception - c#

I would like to make a simple Http request using the Webclient:
public string PostRequest(object json, string contentType, string server)
{
try
{
var request = (HttpWebRequest)WebRequest.Create(server);
request.ContentType = contentType;
request.Method = "POST";
request.Timeout = 10000;
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(JsonConvert.SerializeObject(json));
}
var response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
return streamReader.ReadToEnd();
}
}
catch (Exception e)
{
throw e;
}
}
The problem is that the request.GetRequestStream() part does never return and will always timeout (with the default 100s and the 10s as well). I am using a samsung xcover 4 with android 7 and later android 8.1. the server string works perfectly when copyed into my standard browser on the PC.On the device browser itself it does not work (timeout). The contentType is "application/json".
Is there something I can do to fix this problem or is there another method to send httprequests in xamarin that are not broken?
the server itself is working and I can ping it form my device:
public int PingHost(string nameOrAddress)
{
int pingCount = 0;
Ping pinger = null;
for (int i = 0; i < 4; i++)
{
try
{
pinger = new Ping();
PingReply reply = pinger.Send(nameOrAddress);
pingCount += reply.Status == IPStatus.Success ? 1:0;
}
catch (Exception){ pingCount = - 1; }
finally
{
pinger?.Dispose();
}
if (pingCount == -1) return -1;
}
return pingCount;
}
thanks for your time.

Well I have a working code in my application and it is something like this:
public HttpClient apiClient;
GetType API
public async Task<string> GetServiceData(string srvUrl)
{
try
{
apiClient = new HttpClient(new NativeMessageHandler(throwOnCaptiveNetwork: false, customSSLVerification: false)); // SSL true if you have custom SLL in your API
apiClient.BaseAddress = new Uri(_yourbaseUrl); // Url where the service is hosted
apiClient.DefaultRequestHeaders.Add("",""); //defualt req header key value in case any
var respon = await apiClient.GetAsync(srvUrl).Result.Content.ReadAsStringAsync(); // svrUrl is the name of the api that you want to consume
if (respon != string.Empty)
{
return respon;
}
}
catch (HttpRequestException reqEx)
{
return string.Empty;
}
catch (Exception ex)
{
return string.Empty;
}
}
PostType API
public async Task<string> PostServiceData(string srvUrl, object srvModel)
{
try
{
var myContent = JsonConvert.SerializeObject(srvModel);//your parameter to the API
var stringContent = new StringContent(myContent, Encoding.UTF8, "application/json");
apiClient = new HttpClient(new NativeMessageHandler(throwOnCaptiveNetwork: false, customSSLVerification: true));// SSL true if you have custom SLL in your API
apiClient.BaseAddress = new Uri(_yourbaseUrl); // Url where the service is hosted
apiClient.DefaultRequestHeaders.Add("",""); //defualt req header key value in case any
apiClient.DefaultRequestHeaders.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));//ACCEPT header
var respon = await apiClient.PostAsync(srvUrl, stringContent);
var resReslt = respon.Content.ReadAsStringAsync().Result;
return resReslt;
}
else
return string.Empty;
}
catch (HttpRequestException reqEx)
{
return string.Empty;
}
catch (Exception ex)
{
return string.Empty;
}
Good luck In case of queries revert!

Related

Unauthorized status from mobile Xamarin Forms application with Axelor Rest web-services

I want to connect to the Axelor server with a Xamarin forms application, I use this method to test the rest services connectivity :
Login login = new()
{
UserName = Constants.Login,
Password = Constants.Password
};
// Build authentication string
byte[] bytes = Encoding.UTF8.GetBytes($"{login.UserName}:{login.Password}");
string authorizationString = Convert.ToBase64String(bytes);
// Add headers to the HTTP client
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authorizationString);
// Build HTTP message and send, strRoot = login.jsp
string url = $"{Constants.RestBaseUrl}/{strRoot}";
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, url);
var sessionResponse = await httpClient.SendAsync(message);
/* sessionResponse.IsSuccessStatusCode = true, and sessionResponse.Headers =
{
Set-Cookie: JSESSIONID=E5EA31C3A5CBDF0A1C4B05ED2230679E; Path=/Gradle___com_axelor___axelor_erp_6_3_0_war; HttpOnly
Date: Mon, 14 Nov 2022 19:40:04 GMT
}
*/
sessionResponse.Headers.ToList().ForEach(x =>
httpClient.DefaultRequestHeaders.Add(x.Key, x.Value.FirstOrDefault()));
var rt = $"{Constants.RestBaseUrl}/ws/rest/com.axelor.apps.poultryfarming.db.Hatchery";
var response = await httpClient.GetAsync(rt);
var returnValue = await response.Content.ReadAsStringAsync();
/* returnValue :
<!doctype html><html lang="en"><head><title>HTTP Status 401 – Unauthorized</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 401 – Unauthorized</h1><hr class="line" /><p><b>Type</b> Status Report</p><p><b>Description</b> The request has not been applied because it lacks valid authentication credentials for the target resource.</p><hr class="line" /><h3>Apache Tomcat/8.5.73</h3></body></html>
*/
var stat = response.StatusCode; // return: Unauthorized
var cc = response.IsSuccessStatusCode;
return returnValue;
}
catch (Exception e)
{
throw;
}
but i always get the Unauthorized status !
Can you help me please
When I test with navigator I have correct response like this :
It works well with RestSharp.RestRequest!
Call Axelor rest services with RestClient example : https://github.com/dalmed/Maui-Axelor-Mobile.git
This is my solution :
public class RestClientService : IRestClientService
{
//private readonly ILogger<RestClientService> _logger;
public RestClientService()
{
//_logger = logger;
}
public async Task<bool> LoginAsync(Login login)
{
string jsonString = JsonSerializer.Serialize(login);
try
{
Constants.Cookies = null;
Constants.IsServerConnected = false;
var uri = new Uri($"{Constants.RestBaseUrl}/login.jsp");
var _RestClient = new RestClient(uri);
var request = new RestRequest(uri, Method.Post);
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", login, ParameterType.RequestBody);
RestResponse response = await _RestClient.ExecuteAsync(request);
if (response.IsSuccessStatusCode)
{
Constants.Cookies = response.Cookies;
Constants.IsServerConnected = true;
}
return response.IsSuccessStatusCode;
}
catch (Exception e)
{
// _logger.LogError(e, "LoginError");
throw;
}
}
public async Task<RootData<T>> RestServiceGetAsync<T>(string model, int offset = 0, int limit = 10)
{
try
{
var uri = $"{Constants.RestBaseUrl}/ws/rest/{model}";
var _RestClient = new RestClient(uri);
var request = new RestRequest(uri, Method.Get);
request.AddHeader("Content-Type", "application/json");
if (Constants.Cookies.Any() && Constants.IsServerConnected)
{
string cookie = "";
Constants.Cookies.ToList().ForEach(x => cookie += $"{x.Name}={x.Value}; ");
request.AddHeader("Cookie", cookie);
}
else
{
throw new Exception("The server is not connected !");
}
request.AddParameter("offset", offset, ParameterType.UrlSegment);
request.AddParameter("limit", limit, ParameterType.UrlSegment);
RestResponse response = await _RestClient.ExecuteAsync(request);
if (response.IsSuccessStatusCode)
{
var data = new MemoryStream(Encoding.UTF8.GetBytes(response.Content));
var rslt = await JsonSerializer.DeserializeAsync<RootData<T>>(data);
return rslt;
}
return null;
}
catch (Exception e)
{
//_logger.LogError(e, $"GetModelError: {model}");
throw;
}
}
public async Task<bool> LogoutAsync()
{
try
{
var uri = $"{Constants.RestBaseUrl}/logout";
var _RestClient = new RestClient(uri);
var request = new RestRequest(uri, Method.Get);
request.AddHeader("Content-Type", "application/json");
if (Constants.Cookies.Any() && Constants.IsServerConnected)
{
string cookie = "";
Constants.Cookies.ToList().ForEach(x => cookie += $"{x.Name}={x.Value}; ");
request.AddHeader("Cookie", cookie);
}
else
{
throw new Exception("The server is not connected !");
}
RestResponse response = await _RestClient.ExecuteAsync(request);
return response.IsSuccessStatusCode;
}
catch (Exception e)
{
//_logger.LogError(e, "LogoutError");
throw;
}
}
}

UploadDataTaskAsync never returns

I'm trying to upload data to an external webservice, i'm using the WebClients UploadDataTaskAsync to do this asynchronously. but it never returns. I've tested this using the synchronous call and it will timeout eventually.
public Notification Notify(Notification notification)
{
var messageXml = MessageFactory.Create(notification);
var statusCode = SendWebRequestAsync(messageXml);
notification.ProcessedAttempts++;
if (statusCode.Result == HttpStatusCode.OK)
{
notification.Processed = true;
notification.DateProcessed = DateTime.UtcNow;
}
return notification;
}
private async Task<HttpStatusCode> SendWebRequestAsync(string message)
{
using (var webClient = new WebClient())
{
byte[] data = message.ToUtf8Bytes();
var uri = new Uri(url);
try
{
webClient.UploadDataCompleted += WebClient_UploadDataCompleted;
var result = await webClient.UploadDataTaskAsync(uri, "POST", data);
string response = Encoding.UTF8.GetString(result);
if (response == "")
return HttpStatusCode.OK;
return HttpStatusCode.NoContent;
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
var response = ex.Response as HttpWebResponse;
if (response != null)
{
return response.StatusCode;
}
}
// no http status code available
return HttpStatusCode.ServiceUnavailable; // guess
}
catch (Exception)
{
return HttpStatusCode.InternalServerError;
}
}
}
private void WebClient_UploadDataCompleted(object sender, UploadDataCompletedEventArgs e)
{
Console.WriteLine(e.Result);
}
You're calling statusCode.Result which is the classic ASP.NET deadlock. This makes no sense because you're apparently using async IO to get scalability benefits and then destroying that by blocking.
Don't block.
Also, it looks like HttpClient could reduce the code that you have there a bit.

UploadStringAsync CallBack Return Type

I have a web service where I Post to a URL Asynchronously
public Response uploadXMLData(string destinationUrl, string requestXml,Request req)
{
try
{
Response resp=new Response();
System.Uri uri = new System.Uri(destinationUrl);
using (WebClient client = new WebClient())
{
client.UploadStringCompleted
+= new UploadStringCompletedEventHandler(UploadStringCallback);
client.UploadStringAsync(uri, "POST",requestXml,req);
}
}
catch (Exception ex)
{}
return resp;
}
public void UploadStringCallback(object sender, UploadStringCompletedEventArgs e)
{
Response resp=new Response();
Request req = new Request();
try
{
if (e.Error != null)
{
object objException = e.Error.GetBaseException();
Type _type = typeof(WebException);
if (_type != null)
{
WebException objErr = (WebException)e.Error.GetBaseException();
WebResponse rsp = objErr.Response;
using (Stream respStream = rsp.GetResponseStream())
{
req= (Request)e.UserState;
resp=Utilities.ParseWithoutSoapEnv(respStream);
}
}
else
{
Exception objErr = (Exception)e.Error.GetBaseException();
throw objErr;
}
}
else
{
//Parse e.Result
}
}
catch (Exception ex)
{}
}
The Function Called Utilities.ParseWithoutSoapEnv(respStream); returns Type Response
what I want to do is get the Response from that function, and make it the return value for uploadXMLData
But I can't change the return type of a CallBack Function, so I have no idea what to do.
When someone calls my webservice function, they expect it to return a type of Response, and the Response class I need is being received to the CallBack function..
Hope I made my issue clear
Any help would be appreciated
Things get a little easier if you use the Task Asynchronous Pattern and HttpClient. You'll need to modify your method to return a Task<Response>:
public async Task<Response> UploadXmlDataAsync(
string destinationUrl,
string requestXml,
Request req)
{
try
{
Response resp=new Response();
System.Uri uri = new System.Uri(destinationUrl);
var httpClient = new HttpClient();
var response = await httpClient.PostAsync(Uri, new StringContent(requestxml))
.ConfigureAwait(false);
var responeStream = response.Content.ReadAsStreamAsync().ConfigureAwait(false);
return Utilities.ParseWithoutSoapEnv(responseStream);
}
}
And when you call it higher up the call-stack, you'll need to await that too:
public async Task FooAsync()
{
var parsedResponse = await UploadXmlDataAsync(url, xml, request);
// Do something with response.
}
If you want a synchronous alternative, you can also do:
public Response UploadXmlData(string destinationUrl, string requestXml,Request req)
{
Response resp=new Response();
System.Uri uri = new System.Uri(destinationUrl);
using (WebClient client = new WebClient())
{
var response = client.UploadString(uri, "POST", requestXml, req);
using (var responseStream = new MemoryStream(Encoding.UTF8.GetBytes(response))
{
return Utilities.ParseWithoutSoapEnv(responseStream);
}
}
}

Post request with System.Net.WebClient

I believe the answer is simple but none of the code samples I've found worked...
Basically I'm trying to send a post request using System.Net.WebClient, with a string parameter; But the server gets the parameter as null.
It has to be written in dotnet 2, so I can't use HttpClient (which worked by the way).
client:
using(var client = new WebClient())
{
try
{
var res = client.UploadString(_uri, "POST", "test");
if (res != "test")
return false;
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
return false;
}
service:
public string Post([FromBody]string value)
{
return value;
}
Haven't tested this code, but try it out. You can add more headers, if it throws more errors it might require more specific headers.
using (WebClient client = new WebClient())
{
string yourURL = "http://example.com/example.php";
string PARM= "par1=value1&par=value2";
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
string result= client.UploadString(yourURL, PARM);
if(result != "test"){
return false
}
}

can I check if a file exists at a URL?

I know I can locally, on my filesystem, check if a file exists:
if(File.Exists(path))
Can I check at a particular remote URL?
If you're attempting to verify the existence of a web resource, I would recommend using the HttpWebRequest class. This will allow you to send a HEAD request to the URL in question. Only the response headers will be returned, even if the resource exists.
var url = "http://www.domain.com/image.png";
HttpWebResponse response = null;
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "HEAD";
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
/* A WebException will be thrown if the status of the response is not `200 OK` */
}
finally
{
// Don't forget to close your response.
if (response != null)
{
response.Close();
}
}
Of course, if you want to download the resource if it exists it would most likely be more efficient to send a GET request instead (by not setting the Method property to "HEAD", or by using the WebClient class).
If you want to just copy & paste Justin's code and get a method to use, here's how I've implemented it:
using System.Net;
public class MyClass {
static public bool URLExists (string url) {
bool result = false;
WebRequest webRequest = WebRequest.Create(url);
webRequest.Timeout = 1200; // miliseconds
webRequest.Method = "HEAD";
HttpWebResponse response = null;
try {
response = (HttpWebResponse)webRequest.GetResponse();
result = true;
} catch (WebException webException) {
Debug.Log(url +" doesn't exist: "+ webException.Message);
} finally {
if (response != null) {
response.Close();
}
}
return result;
}
}
I'll keep his observation:
If you want to download the resource, and it exists, it would be more efficient to send a GET request instead by not setting the Method property to "HEAD" or by using the WebClient class.
Below is a simplified version of the code:
public bool URLExists(string url)
{
bool result = true;
WebRequest webRequest = WebRequest.Create(url);
webRequest.Timeout = 1200; // miliseconds
webRequest.Method = "HEAD";
try
{
webRequest.GetResponse();
}
catch
{
result = false;
}
return result;
}
If you are using a unc path or a mapped drive, this will work fine.
If you are using a web address (http, ftp etc) you are better off using WebClient - you will get a WebException if it doesn't exist.
public static bool UrlExists(string file)
{
bool exists = false;
HttpWebResponse response = null;
var request = (HttpWebRequest)WebRequest.Create(file);
request.Method = "HEAD";
request.Timeout = 5000; // milliseconds
request.AllowAutoRedirect = false;
try
{
response = (HttpWebResponse)request.GetResponse();
exists = response.StatusCode == HttpStatusCode.OK;
}
catch
{
exists = false;
}
finally
{
// close your response.
if (response != null)
response.Close();
}
return exists;
}
I had the same problem to solve in asp.net core, I've solved with HttpClient
private async Task<bool> isFileExist(string url)
{
using (HttpClient client = new HttpClient())
{
var restponse = await client.GetAsync(url);
return restponse.StatusCode == System.Net.HttpStatusCode.OK;
}
}
My version:
public bool IsUrlExist(string url, int timeOutMs = 1000)
{
WebRequest webRequest = WebRequest.Create(url);
webRequest.Method = "HEAD";
webRequest.Timeout = timeOutMs;
try
{
var response = webRequest.GetResponse();
/* response is `200 OK` */
response.Close();
}
catch
{
/* Any other response */
return false;
}
return true;
}
WebRequest will waiting long time(ignore the timeout user set) because not set proxy, so I change to use RestSharp to do this.
var client = new RestClient(url);
var request = new RestRequest(Method.HEAD);
request.Timeout = 5000;
var response = client.Execute(request);
result = response.StatusCode == HttpStatusCode.OK;
Thanks for all answers.
And I would like to add my implementation which includes default state when we get errors, for specific cases like mine.
private bool HTTP_URLExists(String vstrURL, bool vResErrorDefault = false, int vTimeOut = 1200)
{
bool vResult = false;
WebRequest webRequest = WebRequest.Create(vstrURL);
webRequest.Timeout = vTimeOut; // miliseconds
webRequest.Method = "HEAD";
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)webRequest.GetResponse();
if (response.StatusCode == HttpStatusCode.OK) vResult = true;
else if (response.StatusCode == HttpStatusCode.NotFound) vResult = false;
else vResult = vResErrorDefault;
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError && ex.Response != null)
{
var resp01 = (HttpWebResponse)ex.Response;
if (resp01.StatusCode == HttpStatusCode.NotFound)
{
vResult = false;
}
else
{
vResult = vResErrorDefault;
}
}
else
{
vResult = vResErrorDefault;
}
}
finally
{
// Don't forget to close your response.
if (response != null)
{
response.Close();
}
}
return vResult;
}
Anoter version with define timeout :
public bool URLExists(string url,int timeout = 5000)
{
...
webRequest.Timeout = timeout; // miliseconds
...
}
This works for me:
bool HaveFile(string url)
{
try
{
using (WebClient webClient = new WebClient())
{
webClient.DownloadString(url);
}
return true;
}
catch (Exception)
{
return false;
}
}

Categories