If you want to get straight to the code, you can find it here:
I was going to think of a clever title for this post, but then I realized that I’d really rather prefer that people be able to find this post when they’re looking for a solution to this problem. All Silverlight application developers (and I’m sure a few Flash developers as well) have come across this problem sooner or later. You see a great web service, you realize it could really use a nice RIA frontend. You set out to build it, only to realize that the builders of the web service didn’t put up a crossdomain.xml or clientaccesspolicy.xml file that lets your Silverlight application make requests to their web service. Now you have one of three choices:
- Convince the web site owners to put your application on their server. Cheeky? Yes. And it could be a looong time before that happens 🙂
- Try selling them on the idea of putting up a cross-domain policy file. In my experience most web sites are amenable to the idea. In this case, you’re stuck waiting for them to put the file on the server
- Write some code on your web server that can proxy your requests to this web service for you. This gets you off running quick, but then you’ve coded up a frontend that relies on this proxy web service
Option 3 gets you up and running fastest, but it also sticks you with the task of migrating your code when the web service eventually adds a cross-domain policy file. Wouldn’t it be nice if there we a way for you to write code very similar to one you’d eventually use? So that you could just flip a switch (or change the fewest lines of code) when the real thing came along? Well I’m glad you asked 🙂 Because of course there is.
First things first, this is NOT a replacement for the built in HttpWebRequest class. In fact, the code here is pure demoware, you have been warned. With that out of the way, let us first begin by looking at our proxy web service. All the code for the service is located in the Knowledgecast.HttpProxy.Server project. The ServiceContract is simple:
The contract has only one method called MakeHttpWebRequest. I’m not going to show off the method code here (link to the code is at the bottom of this post) because all it does is create a new HttpWebRequest based on the paramters in the MakeHttpWebRequest operation. There’s some special handling for headers such as “accept” and “useragent” because HttpWebRequest expects them to be set as properties on the HttpWebRequest instance rather than as additions to the Headers collection.
The other interesting that’s worth noting is the return type. You might have expected to see HttpWebRequest here but there’s a couple of reasons I don’t use it. For one thing, HttpWebRequest is a class that belongs to the .NET framework so it’s not a good idea to use it in our service contract. The other problem is that HttpWebRequest isn’t marked with the DataContract attribute. This is the same reason the ProxyWebRequest class used here does not inherit the WebResponse class like you’d probably expect it to. In fact, ProxyWebRequest is a plain-jane data contract. Here’s what it looks like:
That takes care of the web service. Now lets move on to the client. This is where all the clever code is anyway. We need to make sure it is very easy for you to switch from using this custom proxy service to the real HttpWebRequest when the web site owners eventually put a cross-domain policy online. So we should find a way to plug in to the existing WebRequest infrastructure on the client. Turns out that this is really straightforward to do. First, we start out by implementing a custom version of the WebRequest class. Here’s what our ProxyWebRequest looks like:
We override all of the overrideable properties and methods available in the WebResponse class. The most important method in the above code is our implementation of the BeginGetResponse method. The implementation actually calls the MakeHttpWebRequest service method on the service proxy. As with all calls to web services in Silverlight, the call is asynchronous. In the completed event (the MakeHttpsWebRequestCompleted method) we save the returned ProxyWebResponse into a class member variable. We then call the callback that the client code registered when it called BeginGetResponse. When the EndGetResponse method gets called (usually from the callback method) we instantiate a new ProxyWebResponse (there’s a client version as well, which inherits from WebResponse) based on the ProxyWebResponse returned by the service. The reason we need to do this is because the EndGetResponse method MUST return a type that inherits from WebResponse.
Now the last thing we need to do is make sure client code has a way of getting a handle to our custom ProxyWebRequest. The best way to do this is to register it with the WebRequest class. Before that however, we need to create an IWebRequestCreator that can create ProxyWebRequest objects for WebRequest. So here’s our ProxyWebRequestCreator:
Pretty simple that bit of code. Just creates a new ProxyWebRequest and returns it. Now we’re going to add a static method to our ProxyWebRequest class to register our ProxyWebRequestCreator with a prefix. Here’s that code:
Right! Now that all pieces are in place, what exactly does one need to be able to use this code? Simple. Here’s how you would instantiate a ProxyWebRequest:
Notice the extra p at the front of the address? That’s what ensures we get a ProxyWebRequest instead of a regular HttpWebRequest. Before we use this code however, we must register the phttp prefix with WebRequest. So we would need to do this at some point in our code:
And what do you do when you want to switch back to the regular HttpWebRequest? Simple again. You just change your WebRequest.Create to this:
That’s it! Keep in mind that for the proxy service to work, you will also need a ServiceReferences.ClientConfig in your client project (the sample has an example of this) which registers the proxy service’s endpoint configuration. Here’s the code for this post and a quick sample of how to use it: