Xamarin http webservice issue - xamarin

I m trying to use http request webservice issue is that when we post wrong username and password the login service generate exception and it can't return any value in async calls.

A code snippet would help assist with the problem ...
However using a try catch should help you catch your exception and prevent application from crashing and handling the exceptions accordingly.
As seen in my sample code below I cater for the incorrect details entered / connectivity problems. I peform the http async request then parse the xml to my model handling the exceptions accordingly
var response = await WebRequestHelper.MakeAsyncRequest(url, content);
if (response.IsSuccessStatusCode == true)
{
Debug.WriteLine("Login Successfull" + "result.IsSuccessStatusCode" + response.IsSuccessStatusCode);
var result = response.Content.ReadAsStringAsync().Result;
result = result.Replace("<xml>", "<LoginResult>").Replace("</xml>", "</LoginResult>");
loginResult = XMLHelper.FromXml<LoginResult>(result);
if (loginResult != null)
{
login.Type = ResultType.OK;
login.Result = loginResult;
}
else
{
login.Type = ResultType.WrongDetails;
}
}
else
{
Debug.WriteLine("Login Failed" + "result.IsSuccessStatusCode" + response.IsSuccessStatusCode);
login.Type = ResultType.WrongDetails;
}
}
catch (Exception ex)
{
login.Type = ResultType.ConnectivityProblem;
}
Web Request
public static async Task<HttpResponseMessage> MakeAsyncRequest(string url, Dictionary<string, string> content)
{
var httpClient = new HttpClient();
httpClient.Timeout = new TimeSpan(0, 5, 0);
httpClient.BaseAddress = new Uri(url);
httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type: application/x-www-form-urlencoded", "application/json");
if (content == null)
{
content = new Dictionary<string, string>();
}
var encodedContent = new FormUrlEncodedContent(content);
var result = await httpClient.PostAsync(httpClient.BaseAddress, encodedContent);
return result;

I would recommend wrapping the response in a generic ServiceResponse where you can store the exceptions. await methods can be included in try/catch blocks so the standard process can be followed.
E.G.
public async Task<ServiceResponse<T>> PostAsync<T>(String address, object dto){
var content = Serializer.SerializeObject (dto);
var response = await client.PostAsync (
address,
new StringContent (content));
if (response.IsSuccessStatusCode) {
try {
var responseString = await response.Content.ReadAsStringAsync ();
return new ServiceResponse<T> (Serializer.DeserializeObject<T> (responseString),
response.StatusCode);
} catch (Exception ex) {
return new ServiceResponse<T> (response.StatusCode, ex);
}
} else {
return new ServiceResponse<T> (response.StatusCode);
}
}
With the ServiceResponse defined as :
public class ServiceResponse<T>
{
public HttpStatusCode StatusCode { get; set;}
public T Value { get; set;}
public String Content { get; set;}
public Exception Error {get;set;}
public ServiceResponse(T value, HttpStatusCode httpStatusCode){
this.Value = value;
this.StatusCode = httpStatusCode;
}
public ServiceResponse(HttpStatusCode httpStatusCode, Exception error = null){
this.StatusCode = httpStatusCode;
this.Error = error;
}
}
This will give you a clean way of managing all your HTTP responses and any errors that may occur.

Related

How do I to execute a function on background in Xamarin?

I am trying to execute a function on background when my app will open, to do this, I am trying to create an async function with task but I cannot do it works.
How do I to fix it ?
Xamarin OnStart
protected override void OnStart(){
DefineConcursoSession();
}
//execute in background
private async void DefineConcursoSession(){
ConcursoDTO dto = await ConcursoService.GetConcursoAtivo();
//save session
}
HttpClient
public async static Task<ConcursoDTO> GetConcursoAtivo(){
String ENDPOINT = "/GetConcursoAtivo";
String URL_FINAL = URL_CONTROLLER + ENDPOINT;
ConcursoDTO dto = new ConcursoDTO();
try
{
HttpClient hClient = new HttpClient();
hClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
hClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", BasicAuth.getHash());
//get
HttpResponseMessage response = hClient.GetAsync(URL_FINAL).GetAwaiter().GetResult();
var resultContent = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
//Console.WriteLine("Content: " + resultContent);
if (response.StatusCode == HttpStatusCode.OK){
JObject jo = JObject.Parse(resultContent);
dto = JsonConvert.DeserializeObject<ConcursoDTO>(jo["Concurso"].ToString());
}
}
catch (Exception e)
{
Debug.WriteLine("Erro: GetConcursoAtivo:-> " + e.Message);
}
return dto;
}

Poper way to make a HTTPClient PostAsync and GetAsync?

I want to make a proper HTTPClient request. I have a code but I am always getting so may exceptions like:
Java.IO.IOException: Socket closed
System.OperationCanceledException: The operation was canceled.
Java.Net.SocketException: Connection reset
Java.Net.SocketException: Software caused connection abort
Java.Net.UnknownHostException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
Java.Net.UnknownHostException: Unable to resolve host "tbs.scratchit.ph": No address associated with hostname
Java.IO.IOException: isConnected failed: ETIMEDOUT (Connection timed out)
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?
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.
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

TaskContinuation.cs not found exception while accessing WebAPI Task

I'm trying to fetch records from a db cursor from the Client app.
Debugging Web API shows that the Cursor returns records but when returning to the Client it throws mscorlib.pdb not loaded window and clicking on Load option it throws TaskContinuation.cs not found exception
Code snippets as below ( removed irrelevant codes for readability )
WebAPI
[HttpPost("{values}")]
public async Task<ActionResult> Post([FromBody] JToken values)
{
// code removed for readility
string[] cursors = { };
cursors = await cursor.GetRpts();
CursorClass firstCursor = JsonConvert.DeserializeObject<CursorClass>(cursors[0]);
return new OkObjectResult(cursors);
}
public async Task<string[]> GetRpts()
{
try
{
DataTable[] dataTables;
CursorClass[] cursorClasses = new CursorClass[5];
//stripped some code
using (DataAccess dataAccess = new DataAccess()
{
ParamData = PrepareDoc(),
ProcedureName = Constants.Rpt,
RecordSets = this.CursorNumbers,
})
{
Int32 errorNumber = await dataAccess.RunComAsync();
dataTables = dataAccess.TableData;
};
//fetching code stripped off
string[] _cursors = Array.ConvertAll(cursorClasses, JsonConvert.SerializeObject);
return _cursors;
}
catch (Exception ex)
{
string tt = ex.Message;
}
}
public async Task<Int32> RunComAsync()
{
Int32 returnValue = 0;
try
{
//open db connection
//---------- Running the Command in asysnc mode ----------
Task<int> task = new Task<int>(oracleCommand.ExecuteNonQuery);
task.Start();
returnValue = await task;
//--------------------------------------------------------
OracleRefCursor[] refCursor = { null, null, null, null, null };
for (int _sub = 0; _sub < RecordSets; _sub++)
{
//DT declaration / connection code removed
dataAdapter.Fill(dataTable, refCursor[_sub]);
TableData[_sub] = dataTable;
}
}
catch (Exception ex)
{
return LogMsg(ex);
}
finally
{
this.Dispose(true);
}
CloseConnection();
return LogMsg(null,"Successful Operation");
}
Client
private async Task<HttpStatusCode> CallService()
{
HttpResponseMessage _response = null;
try
{
using (HttpRequestMessage requestMessage = new HttpRequestMessage()
{
Content = new System.Net.Http.StringContent(JsonRepo, System.Text.Encoding.UTF8, HeaderJson),
RequestUri = new Uri(UriString),
Method = HttpMethod.Post,
})
{
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Utils.TOKEN) ;
_response = await httpClient.SendAsync(requestMessage);
if (_response.IsSuccessStatusCode)
{
string httpResponse = await _response.Content.ReadAsStringAsync();
httpString = JsonConvert.DeserializeObject<string[]>(httpResponse);
}
}
}
return ErrorCode;
}
Is that something related to async operation? while debugging the API it confirms the Datatable with records . Any inputs are deeply appreciated.
error image
TIA

Connect to Server using xamarin forms

I'm developing Xamarin Cross platform application. I'm trying to connect to server (http://test.net/login/clientlogin), I need to send these fields (password = "xyz"; platform = iphone; (useremail) = "test#test.com";) along with the request. So that server will check these parameters and returns XML. But we don't know how to add these fields to the request.
When i open the above string url (http://*****/login/clientlogin) i am getting login screen, with in that we have username, password and platform text fields.
Thanks in advance!!!..
This should get you started presuming you are adding the values as headers in the request:
public class TestClient
{
HttpClient client;
public TestClient(){
this.client = new HttpClient ();
}
public void AddHeadersAndGet(){
client.DefaultRequestHeaders.Add ("username", "whatevertheusernameis");
this.GetAsync<WhateverObjectTypeYouAreReceiving> ("theurloftheservice");
}
public async Task<T> GetAsync<T>(string address){
HttpResponseMessage response = null;
response = await client.GetAsync (address);
if (response.IsSuccessStatusCode) {
try {
var responseString = await response.Content.ReadAsStringAsync ();
return new T (Serializer.DeserializeObject<T> (responseString),
response.StatusCode);
} catch (Exception ex) {
}
} else {
}
}
}
The key line for you is:
client.DefaultRequestHeaders.Add ("username", "whatevertheusernameis");

How can i return Json Result + Web api + validate model + actionfilters +OnActionExecuting method

string message = string.Empty;
public override void OnActionExecuting(HttpActionContext actionContext)
{
var modelState = actionContext.ModelState;
if (!modelState.IsValid)
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
foreach (var key in modelState.Keys)
{
var state = modelState[key];
if (state.Errors.Any())
{
message = message + state.Errors.First().ErrorMessage;
}
}
}
Here i want to return message variable with Jsonresult, please help me on it.
Try this
public override void OnActionExecuting(HttpActionContext context)
{
var modelState = context.ModelState;
if (!modelState.IsValid)
{
var errors = new JObject();
foreach (var key in modelState.Keys)
{
var state = modelState[key];
if (state.Errors.Any())
{
errors[key] = state.Errors.First().ErrorMessage;
}
}
context.Response = context.Request.CreateResponse<JObject>(HttpStatusCode.BadRequest, errors);
}
}
From the client ajax request, on error, get the responseText to process the validation error messages.
You might want to pick a HttpStatusCode based on what you are trying to do, since the

Resources