Implementing HttpWebRequest Async calls - c#

I have this code
using (var stream = new StreamWriter(request.GetRequestStream(), Encoding))
stream.Write(body.ToString());
I need to make it asynchronous. As far as I understand it, this means I need to change the call to request.GetRequestStream() to the asychronous.BeginGetRequestStream(). I have seen this example but cannot figure out how to apply that to this scenario. Can someone help?

The documentation has a good example (http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetrequeststream(v=vs.100).aspx):
using System;
using System.Net;
using System.IO;
using System.Text;
using System.Threading;
class HttpWebRequestBeginGetRequest
{
private static ManualResetEvent allDone = new ManualResetEvent(false);
public static void Main(string[] args)
{
// Create a new HttpWebRequest object.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.contoso.com/example.aspx");
request.ContentType = "application/x-www-form-urlencoded";
// 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);
// 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 static void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
Console.WriteLine("Please enter the input data to be posted:");
string postData = Console.ReadLine();
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Write to the request stream.
postStream.Write(byteArray, 0, postData.Length);
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private static 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();
}

you can understand by this code.
The program defines two classes for its own use, the RequestState class, which passes data across asynchronous calls, and the ClientGetAsync class, which implements the asynchronous request to an Internet resource.
The RequestState class preserves the state of the request across calls to the asynchronous methods that service the request. It contains WebRequest and Stream instances that contain the current request to the resource and the stream received in response, a buffer that contains the data currently received from the Internet resource, and a StringBuilder that contains the complete response. A RequestStateis passed as the state parameter when the AsyncCallback method is registered with WebRequest.BeginGetResponse.
The ClientGetAsync class implements an asynchronous request to an Internet resource and writes the resulting response to the console. It contains the methods and properties described in the following list.
The allDone property contains an instance of the ManualResetEvent class that signals the completion of the request.
The Main() method reads the command line and begins the request for the specified Internet resource. It creates the WebRequest wreq and the RequestState rs, calls BeginGetResponse to begin processing the request, and then calls the allDone.WaitOne()method so that the application will not exit until the callback is complete. After the response is read from the Internet resource, Main() writes it to the console and the application ends.
The showusage() method writes an example command line on the console. It is called by Main() when no URI is provided on the command line.
The RespCallBack() method implements the asynchronous callback method for the Internet request. It creates the WebResponse instance containing the response from the Internet resource, gets the response stream, and then starts reading the data from the stream asynchronously.
The ReadCallBack() method implements the asynchronous callback method for reading the response stream. It transfers data received from the Internet resource into the ResponseData property of the RequestState instance, then starts another asynchronous read of the response stream until no more data is returned. Once all the data has been read, ReadCallBack() closes the response stream and calls the allDone.Set() method to indicate that the entire response is present in ResponseData.
using System;
using System.Net;
using System.Threading;
using System.Text;
using System.IO;
// The RequestState class passes data across async calls.
public class RequestState
{
const int BufferSize = 1024;
public StringBuilder RequestData;
public byte[] BufferRead;
public WebRequest Request;
public Stream ResponseStream;
// Create Decoder for appropriate enconding type.
public Decoder StreamDecode = Encoding.UTF8.GetDecoder();
public RequestState()
{
BufferRead = new byte[BufferSize];
RequestData = new StringBuilder(String.Empty);
Request = null;
ResponseStream = null;
}
}
// ClientGetAsync issues the async request.
class ClientGetAsync
{
public static ManualResetEvent allDone = new ManualResetEvent(false);
const int BUFFER_SIZE = 1024;
public static void Main(string[] args)
{
if (args.Length < 1)
{
showusage();
return;
}
// Get the URI from the command line.
Uri httpSite = new Uri(args[0]);
// Create the request object.
WebRequest wreq = WebRequest.Create(httpSite);
// Create the state object.
RequestState rs = new RequestState();
// Put the request into the state object so it can be passed around.
rs.Request = wreq;
// Issue the async request.
IAsyncResult r = (IAsyncResult) wreq.BeginGetResponse(
new AsyncCallback(RespCallback), rs);
// Wait until the ManualResetEvent is set so that the application
// does not exit until after the callback is called.
allDone.WaitOne();
Console.WriteLine(rs.RequestData.ToString());
}
public static void showusage() {
Console.WriteLine("Attempts to GET a URL");
Console.WriteLine("\r\nUsage:");
Console.WriteLine(" ClientGetAsync URL");
Console.WriteLine(" Example:");
Console.WriteLine(" ClientGetAsync http://www.contoso.com/");
}
private static void RespCallback(IAsyncResult ar)
{
// Get the RequestState object from the async result.
RequestState rs = (RequestState) ar.AsyncState;
// Get the WebRequest from RequestState.
WebRequest req = rs.Request;
// Call EndGetResponse, which produces the WebResponse object
// that came from the request issued above.
WebResponse resp = req.EndGetResponse(ar);
// Start reading data from the response stream.
Stream ResponseStream = resp.GetResponseStream();
// Store the response stream in RequestState to read
// the stream asynchronously.
rs.ResponseStream = ResponseStream;
// Pass rs.BufferRead to BeginRead. Read data into rs.BufferRead
IAsyncResult iarRead = ResponseStream.BeginRead(rs.BufferRead, 0,
BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs);
}
private static void ReadCallBack(IAsyncResult asyncResult)
{
// Get the RequestState object from AsyncResult.
RequestState rs = (RequestState)asyncResult.AsyncState;
// Retrieve the ResponseStream that was set in RespCallback.
Stream responseStream = rs.ResponseStream;
// Read rs.BufferRead to verify that it contains data.
int read = responseStream.EndRead( asyncResult );
if (read > 0)
{
// Prepare a Char array buffer for converting to Unicode.
Char[] charBuffer = new Char[BUFFER_SIZE];
// Convert byte stream to Char array and then to String.
// len contains the number of characters converted to Unicode.
int len =
rs.StreamDecode.GetChars(rs.BufferRead, 0, read, charBuffer, 0);
String str = new String(charBuffer, 0, len);
// Append the recently read data to the RequestData stringbuilder
// object contained in RequestState.
rs.RequestData.Append(
Encoding.ASCII.GetString(rs.BufferRead, 0, read));
// Continue reading data until
// responseStream.EndRead returns –1.
IAsyncResult ar = responseStream.BeginRead(
rs.BufferRead, 0, BUFFER_SIZE,
new AsyncCallback(ReadCallBack), rs);
}
else
{
if(rs.RequestData.Length>0)
{
// Display data to the console.
string strContent;
strContent = rs.RequestData.ToString();
}
// Close down the response stream.
responseStream.Close();
// Set the ManualResetEvent so the main thread can exit.
allDone.Set();
}
return;
}
}

Related

Getting data back from an HttpWebRequest.BeginGetResponse callback

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.

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 does my 2 AsyncCallbacks behave like Synchronous calls

I believe I've set this up correctly. Can somebody see anything wrong with this code. Should it execute IAsyncResult asyncResult1 and then immediate move to IAsyncResult asyncResult2? The behavior is that it invokes asyncResult1 (calling the ExecuteAsyncRequest) the rest service keeps it for a bit and then returns it and the next one is called. Shouldn't it just BeginGetResponse and then move on to the next call?
The WCF Rest Service web method is:
public Stream CheckOutForMaster(Stream clientServerXmlStream)
{
//Logic 1: Checks if it's between a set 30 second window.
//Logic 2: Processes more logic
//Logic 3: Holding pattern until the 30 second window is complete. Thus allowing multiple calls to be made via other connections.
//Logic 4: Once 30 second window is complete. All connections have saved their data to a database and each connection will retrieve all data from all connects.
}
Client side test code:
[TestClass]
public class sccTests
{
public static ManualResetEvent allDone = new ManualResetEvent(false);
const int BUFFER_SIZE = 1024;
const int DefaultTimeout = 2 * 60 * 1000; // 2 minutes timeout
List<XDocument> asyncClientServers;
[TestMethod]
public void CheckoutForMaster_OneClientServer_ReturnsAllMasterStatus()
{
string urlTest = CombineWithSccBaseUrl("/v1/clientservers/checkout");
...
IAsyncResult asyncResult1 = ExecuteAsyncRequest(urlTest, xmlPayloadAllMaster);
IAsyncResult asyncResult2 = ExecuteAsyncRequest(urlTest, xmlPayloadAllWait);
}
private IAsyncResult ExecuteAsyncRequest(string url, string payload)
{
try
{
byte[] bytes = Encoding.UTF8.GetBytes(payload);
Uri uri = new Uri(url);
// Create a HttpWebrequest object to the desired URL.
HttpWebRequest myHttpWebRequest1 = (HttpWebRequest)WebRequest.Create(uri);
myHttpWebRequest1.Method = "POST";
myHttpWebRequest1.CachePolicy = new RequestCachePolicy( RequestCacheLevel.NoCacheNoStore);
myHttpWebRequest1.ContentLength = bytes.Length;
myHttpWebRequest1.ContentType = "application/xml;charset=UTF-8";
myHttpWebRequest1.Timeout = 105000;
using (Stream putStream = myHttpWebRequest1.GetRequestStream())
{
putStream.Write(bytes, 0, bytes.Length);
}
// Create an instance of the RequestState and assign the previous myHttpWebRequest1
// object to it's request field.
RequestState myRequestState = new RequestState();
myRequestState.request = myHttpWebRequest1;
// Start the asynchronous request.
IAsyncResult result = myHttpWebRequest1.BeginGetResponse(new AsyncCallback(RespCallback), myRequestState);
}
catch (WebException e)
{
string t = e.Message;
}
catch (Exception e)
{
string t = e.Message;
}
return null;
}
private void RespCallback(IAsyncResult asynchronousResult)
{
try
{
// State of request is asynchronous.
RequestState myRequestState = (RequestState)asynchronousResult.AsyncState;
HttpWebRequest myHttpWebRequest2 = myRequestState.request;
myRequestState.response = (HttpWebResponse)myHttpWebRequest2.EndGetResponse(asynchronousResult);
// Read the response into a Stream object.
Stream responseStream = myRequestState.response.GetResponseStream();
myRequestState.streamResponse = responseStream;
if(myRequestState.response != null && myRequestState.response.StatusCode == HttpStatusCode.OK)
{
StreamReader reader = new StreamReader(myRequestState.response.GetResponseStream(), Encoding.GetEncoding(1251));
XDocument xResult = XDocument.Load(reader);
asyncClientServers.Add(xResult);
}
}
catch (WebException e)
{
// Need to handle the exception
}
}
}
Documentation for GetRequestStream says:
Your application cannot mix synchronous and asynchronous methods for a particular request. If you call the GetRequestStream method, you must use the GetResponse method to retrieve the response.
It doesn't say what happens if you do try to mix synchronous methods, but seeing as you're getting unexpected results from doing so, you probably want to use BeginGetRequestStream.
This looks suspicious:
using (Stream putStream = myHttpWebRequest1.GetRequestStream())
{
putStream.Write(bytes, 0, bytes.Length);
}
// ... etc
IAsyncResult result = myHttpWebRequest1.BeginGetResponse(
new AsyncCallback(RespCallback), myRequestState);
Looks like you have already made and finished the request before you have called BeginGetResponse()

HttpWebRequest not answering

Im trying to use HttpWebRequest on a WP7 application, but I have a problem. I never get a response from server :/
What am I doing wrong?
Here is the faulty code peace...
Util Class
public class RequestState
{
// This class stores the State of the request.
const int BUFFER_SIZE = 1024;
public string requestData;
public byte[] Data
{
get
{
ASCIIEncoding ascii = new ASCIIEncoding();
byte[] encodedPostData = ascii.GetBytes(this.requestData);
return encodedPostData;
}
}
public byte[] BufferRead;
public HttpWebRequest request;
public HttpWebResponse response;
public RequestState()
{
BufferRead = new byte[BUFFER_SIZE];
requestData = string.Empty;
request = null;
}
}
The method...
private static ManualResetEvent allDone = new ManualResetEvent(false);
private static string PostRequest(string service, string email, string password, string source)
{
// Prepare request.
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(clientLoginUrl);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
// Create an instance of the RequestState and assign the previous myHttpWebRequest1
// object to it's request field.
RequestState myRequestState = new RequestState();
myRequestState.request = request;
myRequestState.requestData = String.Format(postData, service, email, password, source);
// Get the response that will contain the Auth token.
try
{
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), myRequestState);
}
catch (WebException ex)
{
HttpWebResponse faultResponse = ex.Response as HttpWebResponse;
if (faultResponse != null && faultResponse.StatusCode == HttpStatusCode.Forbidden)
throw new IncorrectUsernameOrPasswordException(faultResponse.StatusCode, faultResponse.StatusDescription);
else
throw;
}
// Keep the main thread from continuing while the asynchronous
allDone.WaitOne();
if (myRequestState.response != null)
{
// Check for login failed.
if (myRequestState.response.StatusCode != HttpStatusCode.OK)
throw new LoginFailedException(myRequestState.response.StatusCode, myRequestState.response.StatusDescription);
// Read.
using (StreamReader reader = new StreamReader(myRequestState.response.GetResponseStream()))
return reader.ReadToEnd();
}
else
return string.Empty;
}
private static void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
RequestState requestState = (RequestState)asynchronousResult.AsyncState;
HttpWebRequest request = (HttpWebRequest)requestState.request;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
// Write to the request stream.
postStream.Write(requestState.Data, 0, requestState.requestData.Length);
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), requestState);
}
private static void GetResponseCallback(IAsyncResult asynchronousResult)
{
RequestState requestState = (RequestState)asynchronousResult.AsyncState;
HttpWebRequest request = (HttpWebRequest)requestState.request;
// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
requestState.response = response;
allDone.Set();
}
Have you tried do a request to several different websites without luck?
I had this problem as well, and that was because I missed some header options to the request.
Try download a plugin for etc Mozilla that can sniff your request from the browser to the website, and then add those headers from the request to your headers in the HttpWebRequest.

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)

Categories

Resources