I am trying to make a GET request to my backend via a Windows Mobile app that I am working on. The request stops in between and doesn't get through. It ends with no error.
Here's my code:
public void LoginClick() {
var myTask = LoginUser(email, password);
string result = myTask.Result;
}
private async Task<string> LoginUser(string email, string password)
{
//Declarations of Variables
string result = "";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://MYmobileservice.azure-mobile.net/api/loginuser?email="+email+"&password="+password);
request.ContinueTimeout = 4000;
request.Credentials = CredentialCache.DefaultNetworkCredentials;
//Add headers to request
request.Headers["Content-Type"] = "application/json";
request.Headers["ACCEPT"] = "application/json";
request.Headers["X-ZUMO-APPLICATION"] = "<SERVER-KEY-THE-APP-NEEDS>";
using (HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync())
{
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
//To obtain response body
using (Stream streamResponse = response.GetResponseStream())
{
using (StreamReader streamRead = new StreamReader(streamResponse, Encoding.UTF8))
{
result = streamRead.ReadToEnd();
}
}
}
}
return result;
}
Why does it end without completing? Is there anything wrong with my code?
You need to use async all the way up. Here's how to re-write the event handler:
public async void LoginClick() {
string result = await LoginUser(email, password);
}
I'm making the assumption that LoginClick is referenced by a delegate to a Login button's Click event. Notice that I decorated the method with an async modifier. Also, notice that the code is now awaiting the Task returned by LoginUser. You might want to use the convention of LoginUserAsync, but that isn't required.
Wrap your code in the LoginUser method in a try/catch block. Set a breakpoint in the catch block to examine any exceptions thrown. You can look at the documentation of the HttpWebRequest and related types to see what exceptions they could be throwing.
Chances are that just using the proper async code will solve your problem because calling myTask.Result or myTask.Wait() will block the UI thread, which is your most likely problem.
Related
Before I upgraded to the newest .NetCore I was able to run the HttpWebRequest, add the headers and content Type and pull the stream of the JSON file from Twitch. Since the upgrade this is not working. I receive a Web Exception each time I go to get the response Stream. Nothing has changed with twitch because it still works with the old Bot. The old code is below:
private const string Url = "https://api.twitch.tv/kraken/streams/channelname";
HttpWebRequest request;
try
{
request = (HttpWebRequest)WebRequest.Create(Url);
}
request.Method = "Get";
request.Timeout = 12000;
request.ContentType = "application/vnd.twitchtv.v5+json";
request.Headers.Add("Client-ID", "ID");
try
{
using (var s = request.GetResponse().GetResponseStream())
{
if (s != null)
using (var sr = new StreamReader(s))
{
}
}
}
I have done some research and found that I may need to start using either an HttpClient or HttpRequestMessage. I have tried going about this but when adding headers content type the program halts and exits. after the first line here: (when using HttpsRequestMessage)
request.Content.Headers.ContentType.MediaType = "application/vnd.twitchtv.v5+json";
request.Content.Headers.Add("Client-ID", "rbp1au0xk85ej6wac9b8s1a1amlsi5");
You are trying to add a ContentType header, but what you really want is to add an Accept header (your request is a GET and ContentType is used only on requests which contain a body, e.g. POST or PUT).
In .NET Core you need to use HttpClient, but remember that to correctly use it you need to leverage the use of async and await.
Here it is an example:
using System.Net.Http;
using System.Net.Http.Headers;
private const string Url = "https://api.twitch.tv/kraken/streams/channelname";
public static async Task<string> GetResponseFromTwitch()
{
using(var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.twitchtv.v5+json"));
client.DefaultRequestHeaders.Add("Client-ID", "MyId");
using(var response = await client.GetAsync(Url))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync(); // here we return the json response, you may parse it
}
}
}
I can't seem to get async to work the way I want. I'm pretty unfamiliar with it in general, but my research has led me to it. Here's my situation: I have a XAML form I'm loading that needs data from a web service. I can get the data, no problem. The issue is that I want the form to load with a "Please wait. Data loading..." screen that I have made, but nothing loads until the query finishes which can take up to 10 seconds, which is a poor user experience. Can anyone let me know what I'm doing wrong?
In my ViewModel main section, I call LoadData() to get the ball rolling.
I also had a thought...is async what I really want here?
public async void LoadData()
{
IsLoading = Visibility.Visible;
MonitorData downloadInfo = await GetWebApiInfo();
try
{
AssignDataToControls(downloadInfo);
IsLoading = Visibility.Collapsed;
Console.WriteLine("Loaded successfully.");
}
catch (Exception e)
{
IsLoading = Visibility.Collapsed;
Console.WriteLine("Error: " + e);
}
}
private void AssignDataToControls(MonitorData mon)
{
MainPanel.Clear();
mon.MainPanel.ToList().ForEach(x => MainPanel.Add(x));
Information = mon.Information;
MonitorText = mon.MonitorText;
ProgressData = mon.progList;
}
public async Task<MonitorData> GetWebApiInfo()
{
main = new MonitorData();
var url = "::::::::WEB API ADDRESS::::::::";
var request = (HttpWebRequest)WebRequest.Create(url);
//Task<HttpWebRequest> req = await (HttpWebRequest)WebRequest.Create(url);
//HttpWebRequest request = await GetWebRequest(url);
WebResponse response = request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream, Encoding.Unicode);
string responseFromServer = reader.ReadToEnd();
var deserializer = new JavaScriptSerializer();
main = deserializer.Deserialize<MonitorData>(responseFromServer);
reader.Dispose();
response.Dispose();
return main;
}
The compiler will tell you exactly what's wrong with that approach. Specifically, your GetWebApiInfo method is going to run synchronously because you never use await.
In this case, you can use HttpClient to download the information asynchronously. It's a lot easier than mucking around with WebResponse and stuff:
private static readonly HttpClient _client = new HttpClient();
public async Task<MonitorData> GetWebApiInfo()
{
var url = "::::::::WEB API ADDRESS::::::::";
string responseFromServer;
using (var dataStream = await _client.GetStreamAsync())
using (var reader = new StreamReader(dataStream, Encoding.Unicode))
responseFromServer = await reader.ReadToEndAsync();
var deserializer = new JavaScriptSerializer();
return deserializer.Deserialize<MonitorData>(responseFromServer);
}
In general, when you want to "make something async", you should start from the lowest-level APIs. E.g., don't start by marking GetWebApiInfo with async; start with the actual HTTP transfer and call it with await. Then let async/await grow from there.
You may find my NotifyTask<T> type helpful; it allows you to do things like show/hide busy indicators with data binding.
I'm using https://timercheck.io/YOURTIMERNAME/60 to create timer, and when the timer end the API Manager to return both an error code and some JSON content
This is the JSON data when timer end:
{"errorMessage":"504: timer timed out"}
When the timer still countdown:
{"timer":"neo308CCEACbid","request_id":"e54f484e-1e64-11e6-9552-3950b2ec2d5c","status":"ok","now":1463732937,"start_time":1463732935,"start_seconds":180,"seconds_elapsed":2,"seconds_remaining":178,"message":"Timer still running"}
Because of the error code, i get error on Visual Studio and App force close on my Android. I only want to get the errorMessage in JSON. I'm using Visual Studio 2015 and Xamarin to make this project.
Thanks in advance
UPDATE:
I'm using this to get web response
private async Task<string> FetchUserAsync(string url)
{
// Create an HTTP web request using the URL:
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "GET";
// Send the request to the server and wait for the response:
using (WebResponse response = await request.GetResponseAsync())
{
// Get a stream representation of the HTTP web response:
using (var sr = new StreamReader(response.GetResponseStream()))
{
string strContent = sr.ReadToEnd();
return strContent;
}
}
}
And call it like this:
CekTimer dataWaktu = JsonConvert.DeserializeObject<CekTimer>(await FetchUserAsync(url));
I assume you are using HttpClient and GetStringAsync, and that the HttpResponse Status code is a 504 too, like in the Json Content.
The shortcut methods like GetStringAsync all make a call to EnsureSuccessStatusCode, which of cause throws an exception on a 504 (see source here).
You can just make a direct get Request:
var client = new HttpClient();
var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, yourUri));
var json = await response.Content.ReadAsStringAsync();
I found the answer of my problem, because of webservice return error code, just simply use WebException and get the StatusCode like this :
private async Task<string> FetchUserAsync(string url)
{
try
{
// Create an HTTP web request using the URL:
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.ContentType = "application/json";
request.Method = "GET";
// Send the request to the server and wait for the response:
using (WebResponse response = await request.GetResponseAsync())
{
// Get a stream representation of the HTTP web response:
using (var sr = new StreamReader(response.GetResponseStream()))
{
string strContent = sr.ReadToEnd();
return strContent;
}
}
}
catch (WebException e)
{
string a = ((HttpWebResponse)e.Response).StatusCode.ToString();
//Toast.MakeText(this, a, ToastLength.Long).Show();
if (a == "GatewayTimeout")
{
return "{'errorMessage':'504: timer timed out'}";
}
else
{
internetDropDialog();
return "";
}
}
}
I think it isn't the best answer, but it can help you to move on from this problem
Im wondering if theres an easy way to get the response of an async httpwebrequest.
I have already seen this question here but all im trying to do is return the response (which is usually json or xml) in the form of a string to another method where i can then parse it/ deal with it accordingly.
Heres some code:
I have these two static methods here which i think are thread safe as all the params are passed in and there are no shared local variables that the methods use?
public static void MakeAsyncRequest(string url, string contentType)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = contentType;
request.Method = WebRequestMethods.Http.Get;
request.Timeout = 20000;
request.Proxy = null;
request.BeginGetResponse(new AsyncCallback(ReadCallback), request);
}
private static void ReadCallback(IAsyncResult asyncResult)
{
HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
try
{
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult))
{
Stream responseStream = response.GetResponseStream();
using (StreamReader sr = new StreamReader(responseStream))
{
//Need to return this response
string strContent = sr.ReadToEnd();
}
}
manualResetEvent.Set();
}
catch (Exception ex)
{
throw ex;
}
}
Assuming the problem is that you're having a hard time getting to the returned content, the easiest path would likely be using async/await if you can use it. Even better would be to switch to HttpClient if you're using .NET 4.5 since it's 'natively' async.
Using .NET 4 and C# 4, you can still use Task to wrap these and make it a bit easier to access the eventual result. For instance, one option would be the below. Note that it has the Main method blocking until the content string is available, but in a 'real' scenario you'd likely pass the task to something else or string another ContinueWith off of it or whatever.
void Main()
{
var task = MakeAsyncRequest("http://www.google.com", "text/html");
Console.WriteLine ("Got response of {0}", task.Result);
}
// Define other methods and classes here
public static Task<string> MakeAsyncRequest(string url, string contentType)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = contentType;
request.Method = WebRequestMethods.Http.Get;
request.Timeout = 20000;
request.Proxy = null;
Task<WebResponse> task = Task.Factory.FromAsync(
request.BeginGetResponse,
asyncResult => request.EndGetResponse(asyncResult),
(object)null);
return task.ContinueWith(t => ReadStreamFromResponse(t.Result));
}
private static string ReadStreamFromResponse(WebResponse response)
{
using (Stream responseStream = response.GetResponseStream())
using (StreamReader sr = new StreamReader(responseStream))
{
//Need to return this response
string strContent = sr.ReadToEnd();
return strContent;
}
}
"Even better would be to switch to HttpClient if you're using .Net 4.5 since it's 'natively' async." - absolutely right answer by James Manning.
This question was asked about 2 years ago. Now we have .Net Framework 4.5, which provides powerful asynchronous methods. Use HttpClient. Consider the following code:
async Task<string> HttpGetAsync(string URI)
{
try
{
HttpClient hc = new HttpClient();
Task<Stream> result = hc.GetStreamAsync(URI);
Stream vs = await result;
StreamReader am = new StreamReader(vs);
return await am.ReadToEndAsync();
}
catch (WebException ex)
{
switch (ex.Status)
{
case WebExceptionStatus.NameResolutionFailure:
MessageBox.Show("domain_not_found", "ERROR",
MessageBoxButtons.OK, MessageBoxIcon.Error);
break;
//Catch other exceptions here
}
}
}
To use HttpGetAsync(), make a new method that is "async" too. async is required, because we need to use "await" in GetWebPage() method:
async void GetWebPage(string URI)
{
string html = await HttpGetAsync(URI);
//Do other operations with html code
}
Now if you want to get web-page HTML source code asynchronously, just call GetWebPage("web-address..."). Even Stream reading is asynchronous.
NOTE: to use HttpClient .Net Framework 4.5 is required. Also you need to add System.Net.Http reference in your project and add also "using System.Net.Http" for easy access.
For further reading how this approach works, visit: http://msdn.microsoft.com/en-us/library/hh191443(v=vs.110).aspx
Use of Async: Async in 4.5: Worth the Await
Once you go async, you can never go back. From there you only really have access to the async's callback. you can ramp up the complexity of this and do some threading & waithandles but that can be rather a painful endeavor.
Technically, you can also sleep the thread when you need to wait for the results, but I don't recommend that, you may as well do a normal http request at that point.
In C# 5 theyhave async/await commands that will make it easier to get the results of the async call to the main thread.
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);
}
When I run the program contained below the first HTTPS request succeeds, but the second request fails. Both url's are valid and both can be accessed successfully in a browser. Any suggestions as to what needs to be done to access the second url successfully?
using System;
using System.IO;
using System.Net;
public class Program
{
private static void Main(string[] args)
{
var content = "";
bool status;
var url1 = "https://mail.google.com";
var url2 = "https://my.ooma.com";
status = DoHttpRequest(url1, out content);
OutputStatus(url1, status, content);
status = DoHttpRequest(url2, out content);
OutputStatus(url2, status, content);
Console.ReadLine();
}
private static void OutputStatus(string url, bool status, string content)
{
if (status) Console.WriteLine("Url={0}, Status=Success, content length = {1}", url, content.Length);
else Console.WriteLine("Url={0}, Status=Fail, ErrorMessage={1}", url, content);
}
private static bool DoHttpRequest(string url, out string content)
{
content = "";
var request = (HttpWebRequest) WebRequest.Create(url);
try
{
request.Method = "GET";
request.CookieContainer = null;
request.Timeout = 25000; // 25 seconds
var response = (HttpWebResponse) request.GetResponse();
var streamReader = new StreamReader(response.GetResponseStream());
content = streamReader.ReadToEnd();
return true;
}
catch (WebException ex)
{
content = ex.Message;
return false;
}
}
}
Historically, most problems of this description that I've seen occur when you forget to call .Close() on the object returned from GetResponseStream(). The problem exists because when you forget to close the first request, the second request deadlocks waiting for a free connection.
Typically this hang happens on the 3rd request, not the second.
Update: Looking at your repro, this has nothing to do with the order of the requests. You're hitting a problem because this site is sending a TLS Warning at the beginning of the HTTPS handshake, and .NET will timeout when that occurs. See http://blogs.msdn.com/b/fiddler/archive/2012/03/29/https-request-hangs-.net-application-connection-on-tls-server-name-indicator-warning.aspx. The problem only repros on Windows Vista and later, because the warning is related to a TLS extension that doesn't exist in the HTTPS stack on WinXP.
Increse your request TimeOut.
request.Timeout = 60000; //60 second.
May be your network connection is a bit slow. I run with 25 seconds, okay. (Yeah, the second url is a bit longer to get response, than the first one.)