I design a login form in xamarin Form PCL and I want to call a my webservice that will return JSON. For this, I created two functions for the same but both are n is not returning values.
Can you please tell me what I am doing wrong?
async void OnLoginButtonClick(object sender, EventArgs e)
{
if (usernameEntry.Text != "" && passwordEntry.Text != "")
{
var response = GetLoginDetails(usernameEntry.Text,passwordEntry.Text);
var getData = await getDataFromService(usernameEntry.Text, passwordEntry.Text);
}
}
public static async Task<HttpResponseMessage> GetLoginDetails(string username, string password)
{
try
{
var httpClient = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://mywebserverIP/api/Users?Username=" + username + "&Password=" + password);
var response = await httpClient.SendAsync(request);
return response;
}
catch (Exception ex)
{
throw;
}
}
public static async Task<dynamic> getDataFromService(string username, string password)
{
using (var client = new HttpClient())
{
var responseText = await client.GetStringAsync("http://mywebserverIP/api/Users?Username=" + username + "&Password=" + password);
dynamic data = JsonConvert.DeserializeObject(responseText);
return data;
}
}
Thanks for your comment in Advance.
As you not awaiting the first method , request thread will not wait till it returns the value so , 1st change you have to make is to
var response = await GetLoginDetails()
For the second method
var getData = await getDataFromService()
I do not see any issue. I am not sure how you know that this method is not returning any values. Better to log the response of the both the method call and check.
Use await.
First in the
var response = await GetLoginDetails(...
then maybe in the deserializeobject method too (this one i'm not sure)
dynamic data = await Task.Run(() => JsonConvert.DeserializeObject(responseText));
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.
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);
}
}
}
How can I use HttpWebRequest (.NET, C#) asynchronously?
Use HttpWebRequest.BeginGetResponse()
HttpWebRequest webRequest;
void StartWebRequest()
{
webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null);
}
void FinishWebRequest(IAsyncResult result)
{
webRequest.EndGetResponse(result);
}
The callback function is called when the asynchronous operation is complete. You need to at least call EndGetResponse() from this function.
By far the easiest way is by using TaskFactory.FromAsync from the TPL. It's literally a couple of lines of code when used in conjunction with the new async/await keywords:
var request = WebRequest.Create("http://www.stackoverflow.com");
var response = (HttpWebResponse) await Task.Factory
.FromAsync<WebResponse>(request.BeginGetResponse,
request.EndGetResponse,
null);
Debug.Assert(response.StatusCode == HttpStatusCode.OK);
If you can't use the C#5 compiler then the above can be accomplished using the Task.ContinueWith method:
Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse,
request.EndGetResponse,
null)
.ContinueWith(task =>
{
var response = (HttpWebResponse) task.Result;
Debug.Assert(response.StatusCode == HttpStatusCode.OK);
});
Considering the answer:
HttpWebRequest webRequest;
void StartWebRequest()
{
webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), null);
}
void FinishWebRequest(IAsyncResult result)
{
webRequest.EndGetResponse(result);
}
You could send the request pointer or any other object like this:
void StartWebRequest()
{
HttpWebRequest webRequest = ...;
webRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), webRequest);
}
void FinishWebRequest(IAsyncResult result)
{
HttpWebResponse response = (result.AsyncState as HttpWebRequest).EndGetResponse(result) as HttpWebResponse;
}
Greetings
Everyone so far has been wrong, because BeginGetResponse() does some work on the current thread. From the documentation:
The BeginGetResponse method requires some synchronous setup tasks to
complete (DNS resolution, proxy detection, and TCP socket connection,
for example) before this method becomes asynchronous. As a result,
this method should never be called on a user interface (UI) thread
because it might take considerable time (up to several minutes
depending on network settings) to complete the initial synchronous
setup tasks before an exception for an error is thrown or the method
succeeds.
So to do this right:
void DoWithResponse(HttpWebRequest request, Action<HttpWebResponse> responseAction)
{
Action wrapperAction = () =>
{
request.BeginGetResponse(new AsyncCallback((iar) =>
{
var response = (HttpWebResponse)((HttpWebRequest)iar.AsyncState).EndGetResponse(iar);
responseAction(response);
}), request);
};
wrapperAction.BeginInvoke(new AsyncCallback((iar) =>
{
var action = (Action)iar.AsyncState;
action.EndInvoke(iar);
}), wrapperAction);
}
You can then do what you need to with the response. For example:
HttpWebRequest request;
// init your request...then:
DoWithResponse(request, (response) => {
var body = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.Write(body);
});
public static async Task<byte[]> GetBytesAsync(string url) {
var request = (HttpWebRequest)WebRequest.Create(url);
using (var response = await request.GetResponseAsync())
using (var content = new MemoryStream())
using (var responseStream = response.GetResponseStream()) {
await responseStream.CopyToAsync(content);
return content.ToArray();
}
}
public static async Task<string> GetStringAsync(string url) {
var bytes = await GetBytesAsync(url);
return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
I ended up using BackgroundWorker, it is definitely asynchronous unlike some of the above solutions, it handles returning to the GUI thread for you, and it is very easy to understand.
It is also very easy to handle exceptions, as they end up in the RunWorkerCompleted method, but make sure you read this: Unhandled exceptions in BackgroundWorker
I used WebClient but obviously you could use HttpWebRequest.GetResponse if you wanted.
var worker = new BackgroundWorker();
worker.DoWork += (sender, args) => {
args.Result = new WebClient().DownloadString(settings.test_url);
};
worker.RunWorkerCompleted += (sender, e) => {
if (e.Error != null) {
connectivityLabel.Text = "Error: " + e.Error.Message;
} else {
connectivityLabel.Text = "Connectivity OK";
Log.d("result:" + e.Result);
}
};
connectivityLabel.Text = "Testing Connectivity";
worker.RunWorkerAsync();
.NET has changed since many of these answers were posted, and I'd like to provide a more up-to-date answer. Use an async method to start a Task that will run on a background thread:
private async Task<String> MakeRequestAsync(String url)
{
String responseText = await Task.Run(() =>
{
try
{
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
return new StreamReader(responseStream).ReadToEnd();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
}
return null;
});
return responseText;
}
To use the async method:
String response = await MakeRequestAsync("http://example.com/");
Update:
This solution does not work for UWP apps which use WebRequest.GetResponseAsync() instead of WebRequest.GetResponse(), and it does not call the Dispose() methods where appropriate. #dragansr has a good alternative solution that addresses these issues.
public void GetResponseAsync (HttpWebRequest request, Action<HttpWebResponse> gotResponse)
{
if (request != null) {
request.BeginGetRequestStream ((r) => {
try { // there's a try/catch here because execution path is different from invokation one, exception here may cause a crash
HttpWebResponse response = request.EndGetResponse (r);
if (gotResponse != null)
gotResponse (response);
} catch (Exception x) {
Console.WriteLine ("Unable to get response for '" + request.RequestUri + "' Err: " + x);
}
}, null);
}
}
Follow up to the #Isak 's answer, which is very good. Nonetheless it's biggest flaw is that it will only call the responseAction if the response has status 200-299. The best way to fix this is:
private void DoWithResponseAsync(HttpWebRequest request, Action<HttpWebResponse> responseAction)
{
Action wrapperAction = () =>
{
request.BeginGetResponse(new AsyncCallback((iar) =>
{
HttpWebResponse response;
try
{
response = (HttpWebResponse)((HttpWebRequest)iar.AsyncState).EndGetResponse(iar);
}
catch (WebException ex)
{
// It needs to be done like this in order to read responses with error status:
response = ex.Response as HttpWebResponse;
}
responseAction(response);
}), request);
};
wrapperAction.BeginInvoke(new AsyncCallback((iar) =>
{
var action = (Action)iar.AsyncState;
action.EndInvoke(iar);
}), wrapperAction);
}
And then as #Isak follows:
HttpWebRequest request;
// init your request...then:
DoWithResponse(request, (response) => {
var body = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.Write(body);
});
I've been using this for async UWR, hopefully it helps someone
string uri = "http://some.place.online";
using (UnityWebRequest uwr = UnityWebRequest.Get(uri))
{
var asyncOp = uwr.SendWebRequest();
while (asyncOp.isDone == false) await Task.Delay(1000 / 30); // 30 hertz
if(uwr.result == UnityWebRequest.Result.Success) return uwr.downloadHandler.text;
Debug.LogError(uwr.error);
}
I have this method in my Windows Phone 8 app where I get some data from a url
public async static Task<byte[]> getData(string url)
{
HttpClient client = null;
HttpResponseMessage response = null;
Stream stream = null;
byte[] dataBytes = null;
bool error = false;
try
{
Uri uri = new Uri(url);
client = new HttpClient();
response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
stream = await response.Content.ReadAsStreamAsync();
dataBytes = getDataBytes(stream);
if (dataBytes == null)
{
error = true;
}
else if (dataBytes.Length == 0)
{
error = true;
}
}
catch (HttpRequestException )
{
}
if (error)
{
return getData(url); // this is where the issue is
}
return dataBytes;
}
But since the method is an async one, the return type cannot be a Task, like I have done on the line return getData(url); since getData(string) returns Task. Any ideas on how I can rewrite this to make it work?
Awaiting the result of getData may do the trick. Still, I strongly recommand you to rewrite your method with a loop, rather than recursively call the method again. It makes it hard to read, and may lead to unforeseen issues.
public async static Task<byte[]> getData(string url)
{
bool success = false;
byte[] dataBytes = null;
while (!success)
{
try
{
Uri uri = new Uri(url);
var client = new HttpClient();
var response = await client.GetAsync(uri);
response.EnsureSuccessStatusCode();
var stream = await response.Content.ReadAsStreamAsync();
dataBytes = getDataBytes(stream);
success = dataBytes != null && dataBytes.Length > 0;
}
catch (HttpRequestException)
{
}
}
return dataBytes;
}
you can get around the compile error by adding changing the return to the following :
if (error)
{
return await getData(url); // this is where the issue is
}
I hope you do realize that this code will keep on looping as long as no data is returned? having many clients like this could easily overload your server.