How to use HttpWebRequest to send POST request to another web server in Silverlight?

Download Sample Projects (114.64 kb)

Quite some time back I wrote about How to use HttpWebRequest to send POST request to another web server in ASP.Net applications. Now that a lot of silverlight applications are being developed, we have similar need to post data from silverlight applications. The concept is exactly the same that I used in ASP.Net. But there is little difference. Silverlight does not allow blocking synchronous requests. All web requests are asynchronous. That means we have little bit more book keeping to do and manage the thread contexts etc. to make sure that then requests complete and we need to do any UI work in call back methods, we stay in correct thread context.

To keep example simple, I am going to post two values to destination URL using POST method. In the attached project, on Slots.xaml page, I have added a simple button Submit Data. And in the event handler of this button, I initiated request to submit data to Default page of sample web application. The event handler for the click looks as below.


private void SubmitData_Click(object sender, RoutedEventArgs e)
{
 // Prepare web request...
 HttpWebRequest myRequest =
 (HttpWebRequest)WebRequest.Create("http://localhost/SilverGridWeb/Default.aspx");
 myRequest.Method = "POST";
 myRequest.ContentType = "application/x-www-form-urlencoded";
 myRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), myRequest);
}

This code is pretty much same as what I had in ASP.Net application. There is one difference. Instead of calling GetRequestStream method, you will need to call BeginGetRequestStream. This will initiate an asynchronous request. There are two parameters that are passed to this method. First is the callback method that needs to be called when this method completes. Second parameter is any object that you want to pass to callback method. So here I have passed my HttpWebRequest object itself.

Now lets look at what is this callback method GetRequestStreamCallback. I copied the function from Microsoft documentation itself and made some changes to fit my needs.


private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
 HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
 System.IO.Stream postStream = request.EndGetRequestStream(asynchronousResult);
 string strId = "My Id";
 string strName = "My Name";
 string postData = "userid=" + strId;
 postData += ("&username=" + strName);
 byte[] byteArray = System.Text.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);
}

You can see that in callback method, I grabbed the request object that was passed as state to the method call. Then I constructed data that I need to pass with the request that needed to be sent as POST. And then made another async call BeginGetResponse to submit the data and get the response.

Now lets look at what is this callback method for response.


private void GetResponseCallback(IAsyncResult asynchronousResult)
{
 HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
 HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
 Stream streamResponse = response.GetResponseStream();
 StreamReader streamRead = new StreamReader(streamResponse);
 string responseString = streamRead.ReadToEnd();
 // Close the stream object
 streamResponse.Close();
 streamRead.Close();
 // Release the HttpWebResponse
 response.Close();
 Action<string> act = new Action<string>(DisplayResponse);
 this.Dispatcher.BeginInvoke(act, responseString);
}

void DisplayResponse(string msg)
{
 GainersText.Text = msg;
}

Again I passed original HttpWebRequest object to the call method as state. In the call back method, you can grab the request object and then call EndGetResponse to get the resonse stream.

Thread Context and Invalid cross-thread access error

You will notice that in GetResponseCallback method I have called BeginInvoke method on Dispatcher thread. This is very important if you are planning on doing any UI manipulation in the call back methods. The call back methods are invoked on a thread that are separate from the UI thread that initiated the request. So if you try to access any UI element in this callback you will get the following exception thrown.


An unhandled exception ('Unhandled Error in Silverlight Application 
Code: 4004    
Category: ManagedRuntimeError       
Message: System.UnauthorizedAccessException: Invalid cross-thread access.
   at MS.Internal.XcpImports.CheckThread()
   at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value, 
   Boolean allowReadOnlySet, Boolean isSetByStyle, Boolean isSetByBuiltInStyle,
   PropertyInvalidationReason reason)
   at System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value)
   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   at System.Windows.Controls.TextBlock.set_Text(String value)
   at SilverGrid.Views.Stocks.GetResponseCallback(IAsyncResult asynchronousResult)
   at System.Net.Browser.BrowserHttpWebRequest.<>c__DisplayClassd.
    <InvokeGetResponseCallback>b__b(Object state2)
   at System.Threading._ThreadPoolWaitCallback.WaitCallback_Context(Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, 
   ContextCallback callback, Object state)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallbackInternal
   (_ThreadPoolWaitCallback tpWaitCallBack)
   at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback(Object state)     
') occurred in iexplore.exe [7532].

Therefore it is important that from the callback method, you invoke an action request on Dispatcher thread of UI.

comments powered by Disqus

Search

Social

Weather

15.7 °C / 60.3 °F

weather conditions Clear

Monthly Posts

Blog Tags