"arg_targetinvocationexception" - how determine the cause? - xamarin

enter image description here
private HttpClient CreateHttpClient(string UserToken = "")
{
HttpClientHandler handler = new HttpClientHandler();
HttpClient httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromSeconds(20);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Add(AppConfig.HeaderKey_AppToken, AppConfig.HeaderValue_AppToken);
if (!string.IsNullOrEmpty(UserToken))
{
httpClient.DefaultRequestHeaders.Add("UserToken", UserToken);
}
return httpClient;
}
The Exception is occure on "HttpClient httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromSeconds(20);" this line
I have attached image what exact "arg_targetinvocationexception" issue i am facing please check.I am using MAUI And latest preview versio on VS2022 .When i am access this function that time I'm facing "arg_targetinvocationexception" this issue
Main thing when I'm run the application in debugg mode that time It's working fine.But when I'm run the application on Realese mode that time show this error indide a alert box show in attached image.
private async Task SendOTPClicked()
{
try
{
var networkFlag = Common.Instance.IsNetworkConnected();
if (networkFlag)
{
CustomProgressDialog.Instance.ShowLoading(AppResources.Sending_lbl);
string url = $"{AppConfig.ApiBaseUrl}{AppConfig.ApiKeypoints_sendotp}";
string phonenumber = CountryCode.Replace("+", "") + PhoneNumber;
string ApiUrl = $"{url}{phonenumber}";
var response = await RequestProviderService.Instance.PostAsync<ResponseViewModel<string>>(ApiUrl, phonenumber, "", AppConfig.TenantId_Value, "", null);
if (response != null)
{
if (response.Status)
{
await UserDialogs.Instance.AlertAsync(response.Message, AppResources.Title_Success, AppResources.Ok_Flag);
await App.Current.MainPage.Navigation.PushAsync(new EnterOTPView(CountryCode.Replace("+", "") + _phonenumber, User));
CustomProgressDialog.Instance.HideLoading();
}
else
{
string errorMessage = string.IsNullOrEmpty(response.ErrorMessage) ? response.Message : response.ErrorMessage;
CustomProgressDialog.Instance.HideLoading();
if (!string.IsNullOrEmpty(errorMessage))
{
await UserDialogs.Instance.AlertAsync(errorMessage, AppResources.Alert_Label, AppResources.Ok_Flag);
}
}
}
else
{
CustomProgressDialog.Instance.HideLoading();
}
}
else
{
await UserDialogs.Instance.AlertAsync(AppResources.NetworkError_CheckConnection, AppResources.Alert_Label, AppResources.Ok_Flag);
}
}
catch (System.Exception ex)
{
CustomProgressDialog.Instance.HideLoading();
}
}

I have use "AndroidMessageHandler()" and resolve my issue
if(Device.RuntimePlatform == Device.Android)
{
//HttpClientHandler handler = new HttpClientHandler();
var Msghandler = new Xamarin.Android.Net.AndroidMessageHandler();
httpClient = new HttpClient(Msghandler);
}
else
{
httpClient = new HttpClient();
}

Related

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

Httpclient Slow Performance same computer Android Emulator Xamarin

I am using the HttpClient but my results are taking up to 6 seconds coming back from the same machine on the same subnet and ip range of 192.168. When I call the api directly from the ip address the results are more or less instant so why is it so slow with httpclient on the same computer.
I have seen other so's that suggest set to use proxy as false is the best way to go.
I have also tested this on a stock phone and it takes around 8 seconds for the login to be successful on the phone.
private HttpClient _client;
public async Task<String> Getusers()
{
var content = "";
HttpClientHandler hch = new HttpClientHandler();
hch.Proxy = null;
hch.UseProxy = false;
_client = new HttpClient(hch);
var uri = new Uri(Constants.ApiEndPoint + "/Users"); // Your url is here
try
{
var response = await _client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
content = await response.Content.ReadAsStringAsync();
}
}
catch (Exception ex)
{
throw ex;
}
return content;
}
Here is my login method in case anyone can see something wrong with it.
private async void BtnLogin_Clicked(object sender, EventArgs e)
{
string content = await Getusers(); //Sends a GET request to the specified Uri and returns the response body as a string in an asynchronous operation
List<Users> _users = JsonConvert.DeserializeObject<List<Users>>(content); //Deserializes or converts JSON String into a collection of Post
var userName = txtUserName.Text;
var password = txtPassword.Text;
var isValidUser = _users.Where(w => w.UserName == userName && w.password == password).FirstOrDefault();
var driverId = _users.Where(w => w.UserName == userName && w.password == password).FirstOrDefault().ID;
if (isValidUser != null)
{
Application.Current.Properties["driverId"] = driverId;
Application.Current.MainPage = new MainPage();
}
else
{
lblError.Text = "Error your credentials are invalid, please try again";
}
}

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

How to use RESTful service in Xamarin.Forms to fetch JSON data

Since I am new to Xamarin, I would really appreciate if someone could explain me how to consume RESTful service (returning JSON data) using Xamarin Forms with the simplest example.
You can use JSON.net and HTTP request, here is a quick example of how to use the movie database which is a free movie database GET and POST examples, hope this helps:
const string _baseUrl = "http://api.themoviedb.org/3/";
const string _pageString = "&page=";
//GET Example
public static async Task<ObservableCollection<Movie>> GetTopRatedMoviesAsync(int page = 1)
{
HttpClient client = new HttpClient();
//_apiKey = themoviedb api key, page = page size 1 = first 20 movies;
string topRatedUrl = _baseUrl + "movie/top_rated?" + _apiKey + _pageString + page;
HttpResponseMessage result = await client.GetAsync (topRatedUrl, CancellationToken.None);
if (result.IsSuccessStatusCode) {
try{
string content = await result.Content.ReadAsStringAsync ();
ObservableCollection<Movie> MovieList = GetJsonData(content);
//return a ObservableCollection to fill a list of top rated movies
return MovieList;
}catch(Exception ex){
//Model Error
Console.WriteLine (ex);
return null;
}
}
//Server Error or no internet connection.
return null;
}
static ObservableCollection<Movie> GetJsonData(string content){
JObject jresponse = JObject.Parse (content);
var jarray = jresponse ["results"];
ObservableCollection<Movie> movieList = new ObservableCollection<Movie> ();
foreach (var jObj in jarray) {
Movie newMovie = new Movie();
newMovie.Title = (string)jObj["title"];
newMovie.PosterPath = _baseImgUrl + (string)jObj["poster_path"];
newMovie.HighResPosterPath = _baseImgUrl + (string)jObj["poster_path"];
newMovie.Id = (int)jObj["id"];
newMovie.Overview = (string)jObj["overview"];
newMovie.VoteCount = (double)jObj["vote_count"];
newMovie.ReleaseDate = (DateTime)jObj["release_date"];
newMovie.VoteAverage = (float)jObj["vote_average"];
movieList.Add(newMovie);
}
return movieList;
}
//POST Example:
public static async Task<bool> PostFavoriteMovieAsync(Movie movie)
{
try
{
HttpClient client = new HttpClient();
//_sessionId = string with the movie database session.
string tokenUrl = _baseUrl + "account/id/favorite?" + _apiKey + _sessionId;
string postBody = JsonConvert.SerializeObject(new Favorite{
favorite = !movie.Favorite,
media_id = movie.Id,
});
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsync (tokenUrl,
new StringContent (postBody, Encoding.UTF8, "application/json"));
if(response.IsSuccessStatusCode)
return true;
else
return false;
}
catch(Exception ex){
Console.WriteLine (ex.Message);
return false;
}
}

Xamarin http webservice issue

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.

Resources