I have an Xamarin.Android APK.
When installed in a tablet locally at the company, it works perfectly. I already installed it in about 3 tablets and it is working as expected.
The problem is when I send the APK to be installed in a tablet at my customer (it is located in another state), it seems that the HttpClient is not working as expected.
To test it, I'm showing a Toast with the response of the request. It should return the Role of the user.
Locally, it returns the Role as expected. In the customer, it returns an empty string. No error is thrown locally and in the server as well.
Searching on the web, I found that this could be related with a deadlock. So, I put a .ConfigureAwait(false) on my Get method:
public static async Task<string> CheckLoginAsync(string cpf, string password)
{
try
{
_client = new HttpClient();
_client.BaseAddress = new Uri(ApiUrls.Base);
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Vault.CreateToken(cpf));
_client.Timeout = TimeSpan.FromSeconds(Constants.CheckLoginAsyncTimeout);
var url = $"{ApiUrls.UserLoginApp}/{cpf}/{password}";
var result = await _client.GetAsync(url).ConfigureAwait(false);
if (result.IsSuccessStatusCode)
{
var response = await result.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<string>(response);
}
return null;
}
catch (TaskCanceledException tcex)
{
throw new TaskCanceledException("TaskCanceled", tcex.InnerException);
}
catch (Exception ex)
{
throw new LoginUnsuccessfulException("LoginFailedDB", ex.InnerException);
}
}
After that, it started working and the error started in another method. I try to do the same thing using the .ConfigureAwait(false) but the response is coming null:
private async Task<AppBaseData> GetAppBaseDataAsync(string username)
{
try
{
_client = new HttpClient();
_client.BaseAddress = new Uri(ApiUrls.Base);
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Vault.CreateToken(username));
_client.Timeout = TimeSpan.FromSeconds(Constants.LoadBaseDataAsyncTimeout);
var url = $"{ApiUrls.SupportAppBaseData}/{username}";
var result = await _client.GetAsync(url).ConfigureAwait(false);
if (result.IsSuccessStatusCode)
{
var response = await result.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<AppBaseData>(response);
}
return null;
}
catch (TaskCanceledException ex)
{
throw new TaskCanceledException("TaskCanceled", ex.InnerException);
}
catch (Exception ex)
{
throw new DataNotReadedException("BaseDataDB", ex.InnerException);
}
}
I have no idea of what is causing this problem since it works with the same APK locally and in the customer is not working. The customer network have already been changed to a wifi tethering and the behavior still continues.
The above methods are inside a Task.Run().
Related
So I have a WPF application that I want to connect to a RESTful API made with Node.js express server, I have the API on my local pc and the WPF app as well and I want to connect the WPF app to a route in the API called "meals", is there a way to do that?
Yes there is a way to do that
the below code sends a post and a get requests to the API just change the port to whatever port you're running your API on
private static readonly HttpClient client = new HttpClient();
public async void SendPostRequestToAPI(){
// POST REQUEST
try
{
var values = new Dictionary<string, string>
{
{ "thing1", "hello" },
{ "thing2", "world" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://localhost:port", content);
var responseString = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
Console.WriteLine("Error..... " + ex.StackTrace);
}
// GET REQUEST
try
{
var responseString = await client.GetStringAsync("http://localhost:port");
}
catch (Exception ex)
{
Console.WriteLine("Error..... " + ex.StackTrace);
}
}
don't forget to use the following directive
using System.Net.Http;
I'm having a problem with the .NET HttpClient class. Sometimes the snippet below throws a TaskCanceledException, and i can't debug this because is random (I had the bad luck of Apple reject my Xamarin app for that). Can someone explain to me the reason for this exception?
public static HttpResultModel RecoveryPassword(string email)
{
HttpClient httpClient = new HttpClient();
try
{
var url = String.Format(Constants.SERVER_ADDRESS + "/user/forgotPassword/{0}/", email);
var request = new HttpRequestMessage(new HttpMethod("POST"), url)
{
Content = new StringContent(email, Encoding.UTF8, "application/json"),
};
//to be more specific, this line throws the exception
var result = httpClient.SendAsync(request).Result;
string message = result.Content.ReadAsStringAsync().Result;
if (result.IsSuccessStatusCode)
{
var response = JsonConvert.DeserializeObject<HttpResultModel>(message);
response.OperationSuccess = true;
return response;
}
else
{
var response = JsonConvert.DeserializeObject<HttpResultModel>(message);
response.OperationSuccess = false;
return response;
}
}
catch (Exception ex)
{
throw ex;
}
}
}
This is due to either one of the two reasons:
A server disconnection
a timeout by the Http client. The default for HttpClient is 100 seconds.
You can set this to an infinite timespan.
httpClient.Timeout = System.Threading.Timeout.InfiniteTimeSpan;
each request can be then be set to specific timeouts if needed, as the HttpClient
timeout is on a higher level
Sorry if this question has been asked already but I can not seem to find one that relates to my issue. I have a web service built using C# Asp.Net Web API, here I have the following POST method:
[HttpPost]
[Route("AddLocation")]
public void PostLocation(Locations model)
{
using (Entities db = new Entities())
{
C_btblFALocation newLocation = new C_btblFALocation()
{
cLocationCode = model.Code,
cLocationDesc = model.Description
};
db.C_btblFALocation.Add(newLocation);
db.SaveChanges();
}
}
In my Xamarin.Forms project I have my Rest Service Class:
public async Task SaveLocationAsync(Locations item)
{
var uri = new Uri(string.Format(Constants.LocationSaveRestUrl));
try
{
var json = JsonConvert.SerializeObject(item);
var content = new StringContent(json, Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
response = await client.PostAsync(uri, content);
if (response.IsSuccessStatusCode)
{
Debug.WriteLine(#" Location successfully added.");
}
else
{
Debug.WriteLine(#" Oops, there seems to be a problem.");
}
}
catch (Exception ex)
{
Debug.WriteLine(#" ERROR {0}", ex.Message);
}
}
And my URL is set in my Constants class:
public static string LocationSaveRestUrl = "http://172.16.124.18/ArceusService/api/Assets/AddLocation/";
The problem is I keep getting a 404 error. I have tried every way I can think of to set the URL but no luck. The data seems to be passed through fine from debugging but I don't know how the URL should be for a POST method?
Thanks for any help!
How is your client variable declared? Usually you set a BaseAddress and in your Get/PostAsync you only set the actual resource URI.
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://something.com/api/");
var response = await client.GetAsync("resource/7");
}
I've got an Async method that calls an API to retrieve a JSON via HttpClient with the following code block-
//Assemble the url
string url = "https:someapi.com";
//Call API
var http = new HttpClient();
var response = new HttpResponseMessage();
try
{
response = await http.GetAsync(url);
}
catch (HttpRequestException exception)
{
//The server name or address could not be resolved
var dialog = new MessageDialog("The server name or address could not be resolved!");
dialog.Title = "API Response";
dialog.Commands.Add(new UICommand { Label = "Ok", Id = 0 });
var res = await dialog.ShowAsync();
if ((int) res.Id == 0)
{
exception.ExceptionHandled = true;// Cant' do this!
}
}
return result;
This is for an app development. I was trying to make to app more robust so that while there is no internet or data connection the app should should return that it can't call to the API service and show an error rather than crashing. But I just can't find an way to set the ExceptionHandled property to true. Is there a better way to do this?
P.S. The app crashes and debugger breaks when Ok button is clicked
You can use the IsSuccessStatusCode property from HttpClient to validate if it is a successful http response. Instead of catching a HttpRequestException, you can handle the failure in the else statement.
try
{
response = await http.GetAsync(url);
if(response.IsSuccessStatusCode)
{
//handle success
}
else
{
//handle failure
}
}
finally
{
http.Dispose();
}
Furthermore, a rule of thumb is when you use an IDisposable object, you need to wrap it inside a using statement or handle the dispose in the finally block
using(var http = HttpClient())
{
try
{
response = await http.GetAsync(url);
if(response.IsSuccessStatusCode)
{
//handle success
}
else
{
//handle failure
}
}
}
I am having problem in calling the HttpClient post method from WP application.The PostAsync always hangs and does not give any response.The same code works when i try it from WPF application. Here is what I am doing:
Server Web API code
public class GameController : ApiController
{
[HttpPost]
public GameDto CreateGame(GameDto gameDto)
{
try
{
GameManager bl = new GameManager();
gameDto = bl.CreateGame(gameDto);
return gameDto;
}
catch (Exception)
{
throw;
}
}
}
Client WP8 code calling from class library
private async void Button_Click(object sender, RoutedEventArgs e)
{
try
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:59580");
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
GameDto newGame = new GameDto();
newGame.CreatedBy = 1;
newGame.Name = txtGameName.Text;
newGame.GameTypeId = (int)cmbGameType.SelectedValue;
MediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
var response = await client.PostAsync<GameDto>("api/Game/CreateGame", newGame, jsonFormatter);
response.EnsureSuccessStatusCode(); // Throw on error code.
var userDto = await response.Content.ReadAsAsync<GameDto>();
//_products.CopyFrom(products);
MessageBox.Show(userDto.Id.ToString());
}
catch (Exception)
{
throw;
}
}
Checkout This
Answer res.olved my issue.
Use ConfigureAwait
var result = await httpClient.GetStreamAsync("weeklyplan")
.ConfigureAwait(continueOnCapturedContext:false);