Getting data back from an HttpWebRequest.BeginGetResponse callback - c#

I am writing a Windows Phone 8 app that is supposed to send an GET+POST request to a server and parse the answer.
The code I am using to send the request and to get a response back is the following (it is written in a separate static class):
// server to POST to
string url = "http://myserver.com/?page=hello&param2=val2";
// HTTP web request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/x-www-form-urlencoded";
httpWebRequest.Method = "POST";
// Write the request Asynchronously
using (var stream = await Task.Factory.FromAsync<Stream>(httpWebRequest.BeginGetRequestStream,
httpWebRequest.EndGetRequestStream, null))
{
// Create the post data
string postData = "pseudo=pseudo&titre=test&texte=\"Contenu du message\"";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Write the bytes to the stream
await stream.WriteAsync(byteArray, 0, byteArray.Length);
stream.Close();
IAsyncResult ar = httpWebRequest.BeginGetResponse(new AsyncCallback(GetResponsetStreamCallback), httpWebRequest);
}
}
private static void GetResponsetStreamCallback(IAsyncResult callbackResult)
{
HttpWebRequest request = (HttpWebRequest)callbackResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callbackResult);
using (StreamReader httpWebStreamReader = new StreamReader(response.GetResponseStream()))
{
string result = httpWebStreamReader.ReadToEnd();
//For debug: show results
System.Diagnostics.Debug.WriteLine(result);
}
My problem is : I have no idea how to get this answer (the string result) back in my behind-code in my app (or any other method in my app to be honest).
How could I do that?

You can try the following code,
string url = "http://myserver.com/?page=hello&param2=val2";
// HTTP web request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/x-www-form-urlencoded";
httpWebRequest.Method = "POST";
httpWebRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), webRequest);
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest webRequest = (HttpWebRequest)asynchronousResult.AsyncState;
using (var postStream = webRequest.EndGetRequestStream(asynchronousResult))
{
//send yoour data here
}
webRequest.BeginGetResponse(new AsyncCallback(GetResponseCallback), webRequest);
}
void GetResponseCallback(IAsyncResult asynchronousResult)
{
try
{
HttpWebRequest myrequest = (HttpWebRequest)asynchronousResult.AsyncState;
using (HttpWebResponse response = (HttpWebResponse)myrequest.EndGetResponse(asynchronousResult))
{
System.IO.Stream responseStream = response.GetResponseStream();
using (var reader = new System.IO.StreamReader(responseStream))
{
data = reader.ReadToEnd();
}
responseStream.Close();
}
}
catch (Exception e)
{
//Handle Exception
}
else
throw;
}
}

public static string GetPageAsString(Uri address)
{
string result = "";
// Create the web request
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
// Get response
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream(), Constants.EncodingType);
// Read the whole contents and return as a string
result = reader.ReadToEnd();
}
return result;
}

Does it have to be a static class? Because if you have a new webrequest object for each request, then each response will come back into it's own object.v
You need to put the result somewhere that you can access it from the place you want to use it.
e.g. if you put it into another public static variable member then you can read it off where you need to. But you probably need to signal the UI to action it, or bind it to the UI.
If you use a static place to store it, then you will only have one active at a time. Unless you add it to a static list of items or results that you are working with
See also: http://blogs.msdn.com/b/devfish/archive/2011/04/07/httpwebrequest-fundamentals-windows-phone-services-consumption-part-2.aspx

You can: make a global variable in App.xaml.cs:
public string result;
In code use it as
(App.Current as App).result = httpWebStreamReader.ReadToEnd();
If you will need to get notified in your current active page when the result is updated - use delegates after you get the response which will signal to your page.

Related

How to get http content using an given api key like this in C#?

http://ssw.com/profile/?apikey = skdwkdkfkkdj
I tried to use
public async Task<string> GetFromUriAsync(string requestUri, string token)
{
var client = new HttpClient();
client.BaseAddress = new Uri(BaseUri);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("apikey", "=" + token);
HttpResponseMessage response = await client.GetAsync(requestUri);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return responseBody;
}
Then it returns null
Am I missing something or is it just totally wrong?
Thanks
You're trying to pass the API key in the header information of your HTTP request. What you need to do is just pass that whole URL without any additional header information.
IE: use "http://ssw.com/profile?apikey=abcdef" as the requestUri and send token as null. Also, remove the setting of the client.DefaultRequestHeaders.Authorization property. Authorization was meant to be a user/pass system and not a token-based system.
To test this, download Fiddler 4 (https://www.telerik.com/download/fiddler). Once you have fiddler installed, on the "Composer" tab, you can test different queries you need by putting the URL directly into the URL box and clicking "Execute". You'll then be able to use the inspectors to see the responses and figure out where you need to go from there.
Here are the classes I use for HTTP GET and POST operations:
public static string HTTPGET(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
request.Timeout = 100000;
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
Stream responseStream = response.GetResponseStream();
if (responseStream != null)
using (StreamReader resStream = new StreamReader(responseStream))
return resStream.ReadToEnd();
return null;
}
catch (Exception e)
{
Console.WriteLine(url);
Console.WriteLine(e);
return null;
}
}
public static string HTTPPOST(string url, string postData)
{
try
{
HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.ContentType = "x-www-form-urlencoded";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
using (Stream requestStream = webRequest.GetRequestStream())
requestStream.Write(byteArray, 0, byteArray.Length);
using (Stream responseStream = webRequest.GetResponse().GetResponseStream())
if (responseStream != null)
using (StreamReader responseReader = new StreamReader(responseStream))
return responseReader.ReadToEnd();
return null;
}
catch (Exception e)
{
Console.WriteLine(url);
Console.WriteLine(postData);
Console.WriteLine(e);
return null;
}
}

WebRequest on windows phone 7

I have the following class (I take it from an example on the net, the only thing I've modified is that I use an IP address and port instead of a domain name):
public class ConnectionManager
{
private static ManualResetEvent allDone = new ManualResetEvent(false);
private string message = "foobar";
public Action MessageSent;
public Action<string> MessageReceived;
public void SendMessage()
{
// Create a new HttpWebRequest object.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://10.1.91.48:3330/");
request.ContentType = "application/json; charset=utf-8";
request.Accept = "application/json";
// Set the Method property to 'POST' to post data to the URI.
request.Method = "POST";
// start the asynchronous operation
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
MessageSent();
// Keep the main thread from continuing while the asynchronous
// operation completes. A real world application
// could do something useful such as updating its user interface.
allDone.WaitOne();
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(message);
// Write to the request stream.
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
Console.WriteLine(responseString);
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
allDone.Set();
MessageReceived(responseString);
}
}
The code above fails to send the message. If I step, when I'm inside GetRequestStreamCallback I can see inside IAsyncResult the following error:
AsyncWaitHandle = 'asynchronousResult.AsyncWaitHandle' threw an
exception of type 'System.NotSupportedException'
What am I doing wrong? How can I fix this code?
While it's probably not the solution to your problem, you need to get into the habit of placing your IDisposable objects into using blocks, to ensure they get cleaned up even if exceptions happen:
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
using (Stream postStream = request.EndGetRequestStream(asynchronousResult))
{
byte[] byteArray = Encoding.UTF8.GetBytes(message);
// Write to the request stream.
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
}
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
string responseString;
using (HttpWebResponse response = (HttpWebResponse) request.EndGetResponse(asynchronousResult))
{
using (Stream streamResponse = response.GetResponseStream())
{
using (StreamReader streamRead = new StreamReader(streamResponse))
{
responseString = streamRead.ReadToEnd();
Console.WriteLine(responseString);
}
}
}
allDone.Set();
MessageReceived(responseString);
}
As an alternative you could be using RestSharp.
http://restsharp.org/
It makes this sort of thing a lot more trivial. You have to make some slight changes to get it to work on the Windows Phone though:
http://www.tonicodes.net/blog/async-and-restsharp-for-windows-phone-7/
Nothing too crazy.
I ended up using WebClient:
WebClient wc = new WebClient();
wc.DownloadStringCompleted += ReadServerResponse;
wc.DownloadStringAsync(new Uri(url));

Why do I receive this error: The remote server returned an error: (417) Expectation Failed

A friend show me this sample code to implement HTTP POST in C# and did work out in a WINFORM App:
http://www.terminally-incoherent.com/blog/2008/05/05/send-a-https-post-request-with-c/
And implemented in a METRO APP:
// this is what we are sending
string post_data = "user=user#example.com&pass=example123";
// this is where we will send it
string uri = "http://app.proceso.com.mx/win8/login";
// create a request
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
// turn our request string into a byte stream
byte[] postBytes = Encoding.UTF8.GetBytes(post_data);
// this is important - make sure you specify type this way
request.ContentType = "application/x-www-form-urlencoded";
Stream requestStream = await request.GetRequestStreamAsync();
// now send it
requestStream.Write(postBytes, 0, postBytes.Length);
// grab te response and print it out to the console along with the status code
WebResponse response = await request.GetResponseAsync();
//var a = new StreamReader(response.GetResponseStream()).ReadToEnd();
StreamReader requestReader = new StreamReader(response.GetResponseStream());
String webResponse = requestReader.ReadToEnd();
I realized, HttpWebRequest does not contain ProtocolVersion and is throwing me this error in this line:
WebResponse response = await request.GetResponseAsync();
// ERROR: The remote server returned an error: (417) Expectation Failed.
I guess the last property is the solution. How can I solve this problem?
Thanks in advance
I recently wrote a small function to handle the posting of trivial data to a server.
private struct HttpPostParam
{
private string _key;
private string _value;
public string Key { get { return HttpUtility.UrlEncode(this._key); } set { this._key = value; } }
public string Value { get { return HttpUtility.UrlEncode(this._value); } set { this._value = value; } }
public HttpPostParam(string key, string value)
{
this._key = key;
this._value = value;
}
};
private static string PostTrivialData(Uri page, HttpPostParam[] parameters)
{
string pageResponse = string.Empty;
try
{
var request = (HttpWebRequest)WebRequest.Create(page); //create the initial request.
request.Method = WebRequestMethods.Http.Post; //set the method
request.AllowAutoRedirect = true; //couple of settings I personally prefer.
request.KeepAlive = true;
request.ContentType = "application/x-www-form-urlencoded";
//create the post data.
byte[] bData = Encoding.UTF8.GetBytes(string.Join("&", Array.ConvertAll(parameters, kvp => string.Format("{0}={1}", kvp.Key, kvp.Value))));
using (var reqStream = request.GetRequestStream())
reqStream.Write(bData, 0, bData.Length); //write the data to the request.
using (var response = (HttpWebResponse)request.GetResponse()) //attempt to get the response.
if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.NotModified) //check for a valid status (should only return 200 if successful)
using (var reader = new System.IO.StreamReader(response.GetResponseStream()))
pageResponse = reader.ReadToEnd();
}
catch (Exception e)
{
/* todo: any error handling, for my use case failing gracefully was all that was needed. */
}
return pageResponse;
}
Essentially it posts the value pairs defined in the "parameters" argument. Will require a reference and import of the System.Web namespace to compile.
I just tested it with your website and got a response back:
HttpPostParam[] httpparams = {
new HttpPostParam("user", "censored#email.com"),
new HttpPostParam("pass", "example123")
};
string response = PostTrivialData(new Uri("http://app.proceso.com.mx/win8/login"), httpparams);
Let me know if there's any issues.

How do I actually get the response of an async web request from outside the method?

I'm a little confused. I'm trying to post to my web service in an async manner, ideally I want to start the request, show a loading spinner on the UI and then when the async request finishes process the response and either show an error if there is one, or do another operation with the result.
Here is my code, I call the request here and pass some data in.
private void SignInExecute()
{
if (Username == null || Password == null)
{
LoginOutput = "Please provide a username or password.";
}
else
{
this.webService.SendLoginRequest("http://localhost:3000/client_sessions", "username=" + Username + "&password=" + Password);
}
}
And here is the actual web request code:
public void SendLoginRequest(string url, string postdata)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Accept = "application/json";
byte[] byteArray = Encoding.UTF8.GetBytes(postdata);
request.CookieContainer = new CookieContainer();
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
((HttpWebRequest)request).KeepAlive = false;
request.BeginGetResponse(new AsyncCallback(GetLoginResponseCallback), request);
}
private static void GetLoginResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
Console.WriteLine(responseString);
// Close the stream object
streamResponse.Close();
streamRead.Close();
response.Close();
}
So to sum up. I want to be able to return the response back to the object which originally gave the call for the web request to start. Any help?
You need to tell the BeginGetResponse to go back to the same context in which it was called via SynchronizationContext.Current. Something like this (the code does not have proper error checking, so you should think about that properly) (Also, Platinum Azure is correct that you should use a using to let your streams close properly (and guaranteed):
In your SendLoginRequest:
//Box your object state with the current thread context
object[] boxedItems = new []{request, SynchronizationContext.Current};
request.BeginGetResponse(new AsyncCallback(GetLoginResponseCallback),
boxedItems);
The getresponse code:
private static void GetLoginResponseCallback(IAsyncResult asynchronousResult)
{
//MY UPDATE
//Unbox your object state with the current thread context
object[] boxedItems = asynchronousResult.AsyncState as object[];
HttpWebRequest request = boxedItems[0] as HttpWebRequest;
SynchronizationContext context = boxedItems[1] as SynchronizationContext;
// End the operation
using(HttpWebResponse response =
(HttpWebResponse)request.EndGetResponse(asynchronousResult))
{
using(Stream streamResponse = response.GetResponseStream())
{
using(StreamReader streamRead = new StreamReader(streamResponse))
{
string responseString = streamRead.ReadToEnd();
Console.WriteLine(responseString);
//MY UPDATE
//Make an asynchronous call back onto the main UI thread
//(context.Send for a synchronous call)
//Pass responseString as your method parameter
//If you have more than one object, you will have to box again
context.Post(UIMethodToCall, responseString);
}
}
}
}
To implement your UI processing
public static void UIMethodCall(object ObjectState)
{
String response = ObjectState as String;
label1.Text = String.Format("Output: {0}", response);
//Or whatever you need to do in the UI...
}
Now, I would test this out first, though. My understanding of Microsoft's implementation of event driven async was that the response was context-aware, and knew which context to return to. So, before jumping to the assumption that you are not on the same context, test it out by trying to update the UI (this will cause a thread context exception if you are not on the calling (UI) thread)

POST json with Rest APi using webReuest from WP7

I am updating the db table on force.com using Rest API. And i am posting json data to update db table like this.
// preparing webrequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
// adding request headers
request.ContentType = "application/json";
request.Headers["Authorization"] = "OAuth " + token;
request.Headers["X-PrettyPrint"] = "1";
// request method
request.Method = "PATCH";
// start the asynchronous operation
request.BeginGetRequestStream(new AsyncCallback(SaveBeginGetRequestStreamCallBack), request);
private void SaveBeginGetRequestStreamCallBack(IAsyncResult ar)
{
HttpWebRequest webRequest = (HttpWebRequest)ar.AsyncState;
Stream postStream = webRequest.EndGetRequestStream(ar);
(using (StreamWriter sw = new StreamWriter(postStream))
{
sw.Write(postData);
// postData is in json format like: {"Name":"Michel"}
}
postStream.close();
webRequest.BeginGetResponse(new AsyncCallback(SaveBeginGetResponseCallback), webRequest);
}
private void SaveBeginGetResponseCallback(IAsyncResult ar)
{
try
{
HttpWebRequest webRequest = (HttpWebRequest)ar.AsyncState;
HttpWebResponse response;
// End the get response operation
response = (HttpWebResponse)webRequest.EndGetResponse(ar);
Stream streamResponse = response.GetResponseStream();
StreamReader streamReader = new StreamReader(streamResponse);
string Response = streamReader.ReadToEnd();
streamResponse.Close();
streamReader.Close();
response.Close();
}
catch (WebException e)
{
MessageBox.Show(e.Message);
// Error treatment
}
But it is showing bad request error. Is it a right way to send json format over http request.
You are not closing/disposing the postStream prior to calling BeginGetResponse ...
Also, call
sw.Write(data);
Since data is a string. Your call (passing an offset and a count) would be appropriate for a byte array. You are actually calling a formatting overload http://msdn.microsoft.com/en-us/library/fd857wct(v=VS.96).aspx

Categories

Resources