posted by: Ralf Rottmann | posted @ Tuesday, March 11, 2008 11:20 PM | View blog reactions

Microsoft recently made available the long awaited Beta 1 of Silverlight Version 2.0. This new version of Silverlight includes .NET language and framework support bringing cross-platform .NET development to live. Silverlight not only comes with the first iteration of rich controls which allow developers to design great user interfaces but also contains a pretty sophisticated network stack.

In this blog post I'm going to take you through creating a Silverlight application which sends an HTTP POST request out to a (very basic PHP driven) service and prints out the response. While Silverlight implements higher level abstractions for accessing SOAP and REST based services I've seen numerous people asking for HTTP POST request support with parameters transmitted as part of the HTTP request as opposed to URL encoding them (which would be an HTTP GET request then). The popularity might be driven by users who are learning Silverlight programming and simply want to start by replacing traditional HTML forms with a Silverlight front end. Another driver might be the mere existence of "services" which accept HTTP POST requests and have not yet been migrated to a full blown REST model.

I assume you've got a solid understanding of .NET and know how to handle Visual Studio 2008. I also assume you've successfully installed all the bits required to build Silverlight 2.0 Beta 1 apps. (If not, Tim Sneath has a great post outlining what's needed.)

In order for you to easily follow along I've set up a very simple service which accepts two HTTP POST parameters (lastname and firstname) and returns a simple XML structure which - if you successfully submitted HTTP POST parameters - feeds back the input parameters. If not, it replaces them with "null".

The service can be freely accessed at http://www.24100.net/labs/silverservice.php. The root of my web server also services a clientaccesspolicy.xml file which allows any Silverlight application out there to access the service. (See the MSDN article How To Make A Service Available Across Domain Boundaries for details.)

Let's get started.

Fire up Visual Studio 2008 and create a new Silverlight Application. I usually create a Web Application along with it just because it makes testing more easy with the built-in development web server.

In the main application page Page.xaml add a button, name it Execute and hook up an event handler to the Click event:

image

Next add a TextBlock named Log which we are going to use to output debug information. I've arranged everything in a vertical StackPanel to make it look a bit better.

image

This is actually all we are going to do on the user interface side. The rest of the tutorial will focus on coding the HTTP POST request and happen in Page.xaml's code behind file Page.xaml.cs.

Open the code behind file Page.xaml.cs. If you've used Visual Studio's IntelliSense to create the Click event before, you'll find the Execute_Click() handler method stub prepared for you:

image

The HttpWebRequest class we are going to use resides in the System.Net namespace which does not get added to your Silverlight project by default Right-click on References > Add Reference... and manually add the System.Net assembly...

image

... and import the namespace by adding the appropriate Using statement at the top of Page.xaml.cs:

image

Now we are all set to start coding. The first thing we are going to do is creating an instance of System.Uri. We are then going to use the static Create() method of System.Net.WebRequest to factor an instance of type HttpWebRequest:

image

If you've used HttpWebRequest in traditional .NET applications before, you'll find out that the Silverlight implementation does not provide a synchronous GetResponse() member. Instead we do have to use .NET's asynchronous programming model to proceed. This is, where things get a bit more complicated. Before we actually proceed with sending out the HTTP request, we have to set the method - which is POST - and set the way the data gets encoded:

image

As stated above HttpWebRequest offers an asynchronous way to handle HTTP requests and responses. We are starting the request by calling the BeginGetRequestStream() method of our request object. The method expects two parameters: The first one is a callback method of type System.AsyncCallback which gets called once the asynchronous creation of the request stream completed successfully. The second parameter can be any object and represents a state object. Why do we need the second parameter anyway? The problem with our asynchronous operation is that the code inside our asynchronous callback method does not necessarily have access to objects inside the "calling" method. The object provided as the second parameter of BeginGetRequestStream() is available inside the asynchronous callback method via the AsyncState property. If the asynchronous callback method would not require any object from within the "calling scope", it would be perfectly legal to use null as the second parameter.

With that said we are going to submit the our request object itself as the second parameter so we can access it's members within the asynchronous callback method.

Here is the code:

image

Note that RequestProceed() is still underlined because we have not yet implemented it. Just for clarity: We are executing the asynchronous BeginGetRequestStream() method on our HttpWebRequest instance stating that once the operation has completed, we want to proceed with the RequestProceed() method and hand over our HttpWebRequest instance itself via the AsyncState mechanism.

Please be also aware that we are starting and asynchronous request here which will allow us to write (aka POST) data along with it. We are not handling a response, yet!

To get rid of Visual Studio's complain about the non existing RequestProceed() method let's go ahead and create the asynchronous callback method:

image

RequestProceed() must implement AsyncCallback's signature.

In the next step we first want to get back a reference to our initial request object from the calling scope. Remember that we submitted the initial request as the AsyncState parameter of BeginGetRequestStream(). All we need to do is cast it from IAsyncResult's AsyncState property:

image

Now we do need a StreamWriter in order to actually write to the request stream. StreamWriter is part of the System.IO namespace so we got to add a Using statement to our project:

image

StreamWriter's constructor expects a Stream object. We do get this via EndGetRequestStream() which itself expects an object which implements IAsyncResult and represents a pending request for a stream. Thanks god, we got both at hand! In the next line of code we are going to new up a StreamWriter object by calling our request's EndGetRequestStream() method and passing in the IAsyncResult object reference from our "calling scope":

image

We are almost there! With this brand new StreamWriter we can now easily write to the HTTP request stream.

POST parameters are defined in a format which you might very well know from URL encoded parameters. We want to hand in a firstname and a lastname parameter. Here we go:

image

Please do note that we are calling the Close() method which sends the data over the wire and closes the underlying stream. There also is a Flush() method available which sends the data out but does not close the stream. Just bear in mind that at some stage you should actively close any stream to release resources.

At this point we have send out our HTTP POST request to http://www.24100.net/labs/silverservice.php and transmitted two parameters with it. What's left to do is handling the response. Once you've followed along until here, it's an easy one as it again involves asynchronous callbacks.

So the last action inside our request callback method is to kick off handling the response:

image

You recognize the pattern. We are starting the asynchronous response handling by calling the BeginGetResponse() method of our request object. We are defining the ResponseProceed() method to be executed once the asynchronous call completed successfully and again "forward" our initial request via the AsyncState mechanism.

In our asynchronous response handler the first step we do is again casting the initial request via the asyncResult.AsyncState property. We then get an HttpWebResponse instance by calling the requests EndGetResponse() method. Finally we new up a StreamReader for the Stream returned by HttpWebResponse's GetResponseStream() method. Here is the straight forward code:

image

The last and final step is to actually use StreamReader to read the response from the web server:

image

Finally we assign the response to our Silverlight TextBlock control:

image

Here is the browser output after clicking the Execute button:

image

(You can try it out here if you've got Silverlight 2.0 installed!)

This is all we've got to do. In my next post I'm going to guide you through encapsulating all the asynchronous plumbing above into a separate class and using Silverlight's powerful eventing mechanisms to feed back responses to the main UI thread. The service at http://www.24100.net/labs/silverservice.php is available for you to test. Feel free!

 

comments
Michael Sync stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Hey man, nice tutorials.. As you are reading Silverlight forum, I hope you know me. What does that service do? I mean, http://www.24100.net/labs/silverservice.php. If we do "POST" request to that service, the service will insert the record or something??

posted on 3/12/2008 3:21 AM
Ralf stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Michael, thanks for stopping by. ;-) All the "service" really does is returning an XML response with the POST parameters included into the XML document. It's merely there to allow users to simply check whether the HTTP POST actually worked.
posted on 3/12/2008 10:06 AM
jernej stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Hi!
I saw Scot Guthries first tutorial on SL 2. But he used WebClient object to make a http request. When to use HttpWebRequest and when WebClient?
Thanks
posted on 3/12/2008 10:42 PM
Peter Bucher stated:
# re: asynchronous http post with silverlight 2.0 beta 1
@jernej

It makes no difference what to use.
Because of WebClient uses internaly HttpWebRequest.
posted on 3/13/2008 1:39 PM
# Issues accessing (new) YouTube API from Silverlight 2.0
Issues accessing (new) YouTube API from Silverlight 2.0
posted on 3/14/2008 12:11 PM
Michael Sync stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Hello Ralf,

Could you please attach the sample project in your post?? I think HttpWebRequest doesn't work well in SL.
posted on 3/14/2008 3:30 PM
zqjpjxan stated:
# zqjpjxan
zqjpjxan
posted on 3/21/2008 11:24 PM
Een stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Very nice introduction to use HttpwebRequest in Silverlight. Two question though, if you don't mind,

1. Since it is a http "post", can I just simplly use it to upload a very large file to a server, which already accepts the normal html "post" from input form for uploading a local file?

2. in your sample a string is the data, if uploading binary data, does it have to be encoded, like with base64 etc.?

Thank you!
posted on 3/22/2008 9:44 PM
Alan Cobb stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Hi Ralf,

Nice post. I wanted to second Michael's suggestion that it would be great if you could include a downloadable VS2008 sample project.

Thanks,
Alan Cobb
posted on 3/23/2008 8:01 PM
Conor McCarthy stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Hi. Thanks for the tutorial.

When I run it I get an exception thrown at this line:
request.BeginGetRequestStream(new AsyncCallback(ResponseProceed), request);

Exception:
An exception of type 'System.InvalidOperationException' occurred in System.Windows.dll but was not handled in user code

Additional information: Operation is not valid due to the current state of the object.

Do you know where the problem might lie?
posted on 3/28/2008 6:15 PM
Waaahsabi stated:
# re: asynchronous http post with silverlight 2.0 beta 1
I got a small problem with this:

I'm trying to implement some sort of PostBack from Silverlight to its underlying aspx file, but anytime i'm trying to post something to the aspx i get a 404 in the response, though the URL is verifiedly correct and works. Is there a trick to access pages on the same server or am i missing something?
posted on 4/3/2008 11:46 AM
# re: asynchronous http post with silverlight 2.0 beta 1
Fantastic post! This is exactly what I was looking for!
posted on 5/9/2008 3:34 PM
Natasha stated:
# re: asynchronous http post with silverlight 2.0 beta 1
I have found two interesting sources http://fileshunt.com and http://filesfinds.com and would like to give the benefit of my experience to you.
posted on 5/17/2008 1:55 PM
Fileshunt.com stated:
# re: asynchronous http post with silverlight 2.0 beta 1
thanks
posted on 5/17/2008 1:56 PM
nileshlr stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Hi. Thanks for the tutorial.

When I run it I get an exception thrown at this line:
request.BeginGetRequestStream(new AsyncCallback(ResponseProceed), request);

Exception:
An exception of type 'System.InvalidOperationException' occurred in System.Windows.dll but was not handled in user code

Additional information: Operation is not valid due to the current state of the object.

Do you know where the problem might lie?


posted on 5/22/2008 4:38 PM
Ben stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Great post!

One question please: Why does the AsyncCallBack (ResponseProceed in your case) get executed on the same thread as the calling thread?

Thanks in advance
posted on 6/2/2008 12:38 AM
thierry verdier stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Hi Ralf,
Great article, but you have to change the clientaccesspolicy.xml adding this :

http-request-headers="*" as attribute of allow-from node

or your crossdomain.xml adding this line :
<allow-http-request-headers-from domain="*" headers="*" />

without that, POST request are not sent at all.

Thierry
posted on 7/28/2008 2:28 PM
oney stated:
# re: asynchronous http post with silverlight 2.0 beta 1
Hi Ralf,

There are limit on the file size (I failed to upload file bigger than 200M).

And also there is a big problem for WebClient or HttpRequest:
think a user has a pc only with 256M memory and he want to upload 1G file through Silverlight, but these two controls all read all the file content into the httpstream first, then do the real transfer when stream.close() is called (I try use stream.flush for each file block, but failed).

So I have to give up these two controls and do the uploading myself with a hot-dog (read a block and transfer it immediately) style.

-Oney
posted on 7/29/2008 11:54 AM
post your comment
Title *
Name *
Email
Url
Comment *  
Please add 2 and 6 and type the answer here: