When working with Silverlight, we often end up communicating with some form of services. They might be SOAP-based WCF services, which Silverlight handles fine, but lately REST-like services have become a lot more popular, and Silverlight doesn’t always handle them as nicely… They often rely on headers and HTTP verbs other than GET and POST, which Silverlight doesn’t handle very well by default.
In my world, I am currently spending a lot of time working with a Silverlight client that is used in a situation where we use federated security. This requires the client to carry around a token that tells the service who he/she is, and what claims are being made.
In this case, we are using the thinktecture IdentityServer, which after a bit of configuration works very well. It makes it very easy to integrate with using Silverlight, which is nice. All you need to do is do is to make an HTTP GET call to the identity server, passing along the credentials in the form of a basic authentication header. The identity server in turn replies with a token that identifies the client (at least if the credentials are valid). The client can then POST that token to the the service (relying party) who will then use that token to authenticate the client. And after that, everyone is happy, and the service can trust the client being who he/she says he/she is…
So in theory, this all just works, no problems at all. And to be honest, it pretty much does! The actual “session”, and by session I mean the period when the service trusts the client, is limited by the token and kept alive using a cookie. What this means, is that the service puts the token in a cookie which is passed back and forth to the server with every request. The token in turn contains a date and time that defines when it is no longer valid. So all the server has to do is to look at that token every request, and make sure it is still valid…
So what is the problem with this? Well, in my case, and I do believe in a lot of cases, we end up switching from using the browser HTTP stack to using the client HTTP stack. The reasons are a few… It might be because we need to support more verbs than just GET and POST. It might be because we need to use headers. Or it might be because we need to be able to use the returned HTTP status codes. And if you intend to use a REST-like API like we are, switching to the client HTTP stack is pretty much mandatory.
There are two ways of doing this. You can either do it per call, which is a bit annoying, but is done like this
var request = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(new Uri(...));
And if you don’t feel like manually telling it over and over again to use the client HTTP stack, you can just tell the application as a whole to use it. Just do the following somewhere in your code, preferably early on in the Application class
bool httpResult = WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
bool httpsResult = WebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);
You can even narrow it down and tell it so only use the client stack for a certain domain…
Ok, so if you have read my blog before, you know that I don’t write about things that are that easy. There has to be a catch…and there is!
As you switch over to the client stack, you loose a pretty important feature. You loose cookie handling all of the sudden, which is pretty important when you for example are using tokens like in my scenario…
It is however pretty easy to turn on cookie support. All you need to do is to set the CookieContainer property for each one of the HttpWebRequests that you create. The CookieContainer is a simple thing to use, but as I said, you need to set it for every request. And on top of that, it is a good little object and keeps the cookies to itself. So you need to set the CookieContainer property to the same instance every time if you want the cookies to work…
This might not be a massive problem, but should be kept in mind. However, I decided that it was bit of a hassle to keep track of and decided to do it a bit differently…
I started out by looking at the WebRequest.RegisterPrefix() method and found that the second parameter is just an interface. An interface called IWebRequestCreate. Hmm…I can probably implement that and create my own CustomWebRequestCreator…
The IWebRequestCreate interface is really simple, it looks like this
public interface IWebRequestCreate
{
WebRequest Create(Uri uri);
}
Ok, that is really simple. So I created my own, just piggybacking off the existing one, but adding a layer in between
private class CustomWebRequestCreator : IWebRequestCreate
{
public WebRequest Create(Uri uri)
{
var request = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(uri);
return request;
}
}
Now that I had this “layer” in between, I am free to do whatever I want with that request. And whatever I do will be done every time someone creates a new HttpWebRequest…
So, what was it I was doing? Oh yes…adding a cookie container… How about doing it like this
private class CustomWebRequestCreator : IWebRequestCreate
{
private readonly CookieContainer CookieContainer = new CookieContainer();
public WebRequest Create(Uri uri)
{
var request = (HttpWebRequest)System.Net.Browser.WebRequestCreator.ClientHttp.Create(uri);
request.CookieContainer = CookieContainer;
return request;
}
}
That way, as long as I use the same creator, I will get the same CookieContainer. All I need to do now is to register my IWebRequestCreator and I am done…
private void Application_Startup(object sender, StartupEventArgs e)
{
var creator = new CustomWebRequestCreator();
WebRequest.RegisterPrefix("http://", creator);
WebRequest.RegisterPrefix("https://", creator);
...
}
…and all of the sudden, cookie handling just work throughout my application, as well as things like status codes, headers and the use of more HTTP verbs… (…I believe more HTTP verbs work, I am actually just using POST at the moment…let me know if I am wrong…)
So the following code works perfectly, even if it uses headers and status codes, and maybe even cookies behind the scenes…
var request = (HttpWebRequest)WebRequest.Create(uri);
foreach (var header in Headers)
{
request.Headers[header.Key] = header.Value;
}
request.BeginGetResponse(iar =>
{
WebResponse response;
try
{
response = request.EndGetResponse(iar);
}
catch (WebException ex)
{
var response = ex.Response as HttpWebResponse;
var statusCode = response.StatusCode;
LogError(uri, statusCode);
return;
}
catch (Exception ex)
{
LogError(uri, ex);
return;
}
HandleResponse(response);
}, null);
That’s it! I hope it is useful for your future projects. This kind of stuff can really get you stuck if you don’t know what is happening. Using Fiddler makes debugging it a lot easier though…
Cheers!
(No code this time. It is just too little to even bother…)