I have an android app in Xamarin native. I am trying to consume a Restful service from an API in another server.
I have this:
private async Task<string> CreateCellphone(string url, Cellphone cell)
{
string cellphone = JsonConvert.SerializeObject(cell);
HttpContent content = new StringContent(cellphone, Encoding.UTF8, "application/json");
using (HttpClient client = new HttpClient())
{
HttpResponseMessage response = await client.PostAsync(url, content);
string responseMessage = await response.Content.ReadAsStringAsync();
return responseMessage;
}
}
I execute this on a button call like this:
private void RegisterButtonOnClick(object sender, EventArgs e)
{
// Create new GUID
Guid obj = Guid.NewGuid();
// Store the created GUID in a private shared preferences file
var localGUID = Application.Context.GetSharedPreferences("LocalSetup", FileCreationMode.Private);
var guidEdit = localGUID.Edit();
guidEdit.PutString("GUID", obj.ToString());
guidEdit.PutBoolean("IsRegistered", true);
guidEdit.Commit();
// Create the cellphone record into the database for DB admin to activate
_url = Resources.GetString(Resource.String.cellphone_api_url);
Cellphone cell = new Cellphone();
cell.CellphoneId = obj.ToString();
var response = CreateCellphone(_url, cell);
}
But when my code gets to the postAsync method, nothing happens, it just continues without actually sending the code to the endpoint, I have no idea what I might be doing wrong, because all documentation I have on PostAsync tells me this is how to send json data for a Restful Web api endpoint.
Thank you in advance for any pointers.
You need to await the call to CreateCellphone or nothing will happen because the response Task will get disposed of almost immediately. Not sure if you can make your button click method async in Xamarin, but I would try this:
private async void RegisterButtonOnClick(object sender, EventArgs e)
//^^^^^
//Add this
{
//snip
await CreateCellphone(_url, cell);
}
Failing that, there are various way to call an async method synchronously, check this question.
Related
So I'm trying to send a multiform POST to API with http client but it's just hang there indefinetly. I test this code in console and it worked as it should, but then I try to run it like this for the UI
private static async Task<string> ApiTask(...)
{
var SourceStream = File.Open(imgpath,FileMode.Open);
var FileStreamContent = new StreamContent(SourceStream);
FileStreamContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
var client = new HttpClient();
using (var formData = new MultipartFormDataContent())
{
formData.Add(new StringContent("this is a test"),"comment");
formData.Add(new StringContent("Command: detect"),"message");
formData.Add(fileStreamContent, "image","image.jpg");
var response = await client.PostAsync(url,formData).ConfigureAwait(false);
var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
return responseString
}
}
And I'm calling it from the EventHandler
public async void buttnclck(object sender, EventArgs e)
{
var task = await ApiTask(...);
lblresult.Text = task;
}
but as I said the code just stay in de .PostAsync line indefinetly or when a System.Threading.Task.TaskCanceledException is thrown.
So what I missing here? I thing I was handeling the async/await methods just fine but it's clear I'm not. I tried also with .Result but it won't work even and would throw System.AggregateException. So please help, been trying to make it work modifying the code as other suggested responses but still not working
EDIT:
after couple of hours debugging and searching I find out my problem relies in formData.Add(FileStreamContent, "image","image.jpg"); maybe I'm not serializing the image correctly? How can I fix this??
I am trying to post data from my app from a register page to a web service (testing with requestb.in) however when I try to use the below code it puts the app into break mode, then when I use break points to find where the problem is it just shows that "await PostRequest(...)" is causing the problem.
I have installed System.Net.Http on both the Portable project and the android project.
public async Task<JObject> PostAsync(string uri, string data)
{
var httpClient = new HttpClient();
var response = await httpClient.PostAsync(uri, new StringContent(data));
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();
return await Task.Run(() => JObject.Parse(content));
}
Then for the button clicked where this method is called:
async void NextBtnClicked(object sender, EventArgs)
{
await PostAsync("https://requestb.in/MYURL", Username.Text);
}
Username.Text is the string from an entry field in the XAML class, This will recreate my problem
Here is the generic method I made to post data to an API.
As #maccettura pointed out above, it is best practice to reuse HttpClient and I've included that in the code, below.
HttpClient Post
static readonly Lazy<HttpClient> _clientHolder = new Lazy<HttpClient>(() => CreateHttpClient(TimeSpan.FromSeconds(60)));
static HttpClient Client => _clientHolder.Value;
protected static async Task<HttpResponseMessage> PostObjectToAPI<T>(string apiUrl, T data)
{
var stringPayload = await Task.Run(() => JsonConvert.SerializeObject(data)).ConfigureAwait(false);
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");
try
{
return await Client.PostAsync(apiUrl, httpContent).ConfigureAwait(false);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
return null;
}
}
static HttpClient CreateHttpClient(TimeSpan timeout)
{
var client = new HttpClient();
client.Timeout = timeout;
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
return client;
}
This snippet was taken from my BaseHttpClientService.cs that I copy/paste into any app that needs to use HttpClient:
https://github.com/brminnick/XamList/blob/master/XamList/Services/BaseHttpClientService.cs
Troubleshoot your application using UWP so that you can see what kind of exception it is throwing. Try also to downgrade the two Nuget packages.
There is another question about this, but it doesn't have a functioning solution at the end, and the only good answer, for some reason, doesn't work, not for the guy who ask it, not for me either.
This such question is here:
How to post data using HttpClient?
Given the corresponding aclarations, this is the code I have so far:
The methods to call the method who connects with the web server:
private void Button_Click(object sender, System.EventArgs e)
{
//. . . DO SOMETHING . . .
PopulateListView();
//. . . DO SOMETHING ELSE . . .
}
private void PopulateListView()
{
//. . . DO SOMETHING . . .
list = await "http://web.server.url".GetRequest<List<User>>();
//. . . DO SOMETHING ELSE . . .
}
The method than connects with the web server:
public async static Task<T> SendGetRequest<T>(this string url)
{
try
{
var uri = new Uri(url);
HttpClient client = new HttpClient();
//Preparing to have something to read
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("OperationType", "eaf7d94356e7fd39935547f6f15e1c4c234245e4")
});
HttpResponseMessage response = await client.PostAsync(uri, formContent);
#region - - Envio anterior (NO FUNCIONO, SIN USO) - -
//var stringContent = new StringContent("markString");
//var sending = await client.PostAsync(url, stringContent);
//MainActivity.ConsoleData = await client.PostAsync(url, stringContent);
#endregion
//Reading data
//var response = await client.GetAsync(url);
var json = await response.Content.ReadAsStringAsync();
MainActivity.ConsoleData = json.ToString();
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(json);
}
catch(Exception ex)
{
Console.WriteLine("Error: "+ex.ToString());
return default(T);
}
}
You maybe guessed it, but I'm trying to make a method that send some data (through POST) called "markString" to a web-server than receive it and, depending of the "markString" it returns certain json Objects.
This web server is already working properly (I tested it out with some plug-in, it work like it should)
This method is supposed to send the "markString" and receive the data back so then i can use it in the app.
I'm making a Xamarin Android application.
Also have in mind than I don't have any connection problem at all, in fact the app is sending data in an excellent matter when I try to do it using web client, but I want it to send it using HttpClient.
The problem
The code is not returning anything. Any request for information, clarification, question, constructive comments or anything than can lead to an answer would be greatly appreciated too.
Thanks in advance.
Most deadlock scenarios with asynchronous code are due to blocking further up the call stack.
By default await captures a "context" (in this case, a UI context), and resumes executing in that context. So, if you call an async method and the block on the task (e.g., GetAwaiter().GetResult(), Wait(), or Result), then the UI thread is blocked, which prevents the async method from resuming and completing.
void Main()
{
var test = SendGetRequest("http://www.google.com");
test.Dump();
}
public async static Task<string> SendGetRequest(string url)
{
try
{
var uri = new Uri(url);
HttpClient client = new HttpClient();
//Preparing to have something to read
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("OperationType", "eaf7d94356e7fd39935547f6f15e1c4c234245e4")
});
HttpResponseMessage response = await client.PostAsync(uri, formContent);
#region - - Envio anterior (NO FUNCIONO, SIN USO) - -
//var stringContent = new StringContent("markString");
//var sending = await client.PostAsync(url, stringContent);
//MainActivity.ConsoleData = await client.PostAsync(url, stringContent);
#endregion
//Reading data
//var response = await client.GetAsync(url);
var json = await response.Content.ReadAsStringAsync();
return json;
}
catch (System.Exception ex)
{
Console.WriteLine("Error: " + ex.ToString());
return string.Empty;
}
}
I am working on a Windows Phone application. While invoking the below function, after executing this line:
HttpResponseMessage response = await client.GetAsync(connection1).ConfigureAwait(false);
it skips the rest of the code and control goes to the parent function and execute the rest of the code there and come back to this function again. How to fix this problem?
public async void vehicleValidation()
{
//isValidVehicle = true;
var client = new System.Net.Http.HttpClient();
//string connection = "http://mymlcp.co.in/mlcpapp/get_slot.php?vehiclenumber=KL07BQ973";
string connection1 = string.Format("http://mymlcp.co.in/mlcpapp/?tag=GetIsValidUser&employeeId={0}&name={1}",txtVeh.Text,"abc");
HttpResponseMessage response = await client.GetAsync(connection1).ConfigureAwait(false);
//var response = await client.GetAsync(connection1);
// HttpResponseMessage response = client.GetAsync(connection1).Result;
var cont = await response.Content.ReadAsStringAsync();
var floorObj = Newtonsoft.Json.Linq.JObject.Parse(cont);
//var resp = await (new MLCPClient()).GetIsValidUser(txtVeh.Text, "xyz");
if (String.IsNullOrEmpty(floorObj["error"].ToString()) || floorObj["error"].ToString().Equals("true"))
{
isValidVehicle = false;
}
else
{
isValidVehicle = true;
}
}
You should never have async void unless you are writing a event handler, you need to make your function return a Task and then await the function in your parent function.
Read "Async/Await - Best Practices in Asynchronous Programming" for a introduction on the best practices like never doing async void and making your code "async all the way"
I have the following code:
ProgressMessageHandler progress = new ProgressMessageHandler();
progress.HttpSendProgress += new EventHandler<HttpProgressEventArgs>(HttpSendProgress);
HttpRequestMessage message = new HttpRequestMessage();
message.Method = HttpMethod.Post;
message.Content = content;
message.RequestUri = new Uri("http://myaddress");
var client = HttpClientFactory.Create(progress);
sending = client.SendAsync(message);
private void HttpSendProgress(object sender, HttpProgressEventArgs e)
{
//....
}
I want to catch a situation, when "myaddress" is not available. Method HttpSendProgress is called when progress is active, so, I can't check in this method.
Any way to check if "myaddress" is available. I have an idea to start one more thread to check when HttpSendProgress is called last time. But maybe there is a standard method?
I dont think you can check if the address is a working address in the progress event. You need to check the status after the response has come back.
if (response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode.ToString());
}
How to determine a 404 response status when using the HttpClient.GetAsync()