Introduction
When you are making a web request from a Silverlight application the cookies associated with the current browser-server session are automatically sent within each request.
A common scenario is when you have a web site with some kind of a cookie driven authentication implemented and a Silverlight application within your web site that shows different content depending on whether the user is logged in or not. The Silverlight application may use some resources on the server, which are accessible only to authenticated users. The good thing is that if you are logged in the web site and make requests from the Silverlight application the server “knows” that your requests come from an authenticated user. You do not need to login both on the web site and the Silverlight application.
Example
I made a simple example to test if all this stuff really works. I just want to have a simple web site with Form authentication and a Silverlight application which uses a resource from the server. The resource behaves differently when the user is logged in and when not. I won’t describe how I created the web site and the authentication system because you are not limited about the server technology. Currently it is ASP.NET web site with the standard ASP.NET membership. But you can also make it with PHP for example.
Provided my web site and the membership system are ready I create my resource. It is a plain text file which contains "Logged In" if the user is authenticated and "Anonymous" if not. I just create a generic handler with the following content:
<%@ WebHandler Language="C#" Class="IsAuthenticated" %>
using System;
using System.Web;
using System.Web.Security;
public class IsAuthenticated : IHttpHandler
{
#region Properties
public bool IsReusable
{
get
{
return false;
}
}
#endregion
#region Methods
public void ProcessRequest (HttpContext context)
{
context.Response.ContentType = "text/plain";
if ( Membership.GetUser( false ) != null )
{
context.Response.Write( "Logged In" );
}
else
{
context.Response.Write( "Anonumous" );
}
}
#endregion
}
The only thing which I do is to try to get the current user and send different content to the browser depending on whether the current user exists or not. So my resource is ready.
Here is the Silverlight Implementation:
XAML:
<UserControl x:Class="SilverlightChat.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock x:Name="tblTest" Text="not loaded yet" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
</Grid>
</UserControl>
I have only one TextBlock which shows my resource content or possible error information.
Code Behind:
using System;
using System.Net;
using System.Windows.Controls;
using System.IO;
using System.Text;
using System.Threading;
using System.Collections.ObjectModel;
namespace SilverlightChat
{
public partial class Page : UserControl
{
private SynchronizationContext currentContext;
private const string RESOURCE_URL = "your resource URL here";
public Page()
{
InitializeComponent();
this.currentContext = SynchronizationContext.Current;
try
{
HttpWebRequest request = ( HttpWebRequest )WebRequest.Create( new Uri( RESOURCE_URL ) );
request.BeginGetResponse( new AsyncCallback( this.RespCallback ), request );
}
catch ( Exception ex )
{
this.tblTest.Text = ex.Message;
}
}
private void RespCallback( IAsyncResult result )
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;
try
{
using ( HttpWebResponse response = ( HttpWebResponse )request.EndGetResponse( result ) )
{
if ( response.StatusCode == HttpStatusCode.OK )
{
Stream responseStream = response.GetResponseStream();
using ( responseStream )
{
StreamReader readStream = new StreamReader( responseStream, Encoding.UTF8 );
using ( readStream )
{
this.currentContext.Post( this.SetText, readStream.ReadToEnd() );
}
}
}
else
{
this.currentContext.Post( this.SetText, response.StatusCode.ToString() );
}
}
}
catch ( Exception ex )
{
this.currentContext.Post( this.SetText, ex.Message );
}
}
private void SetText( object state )
{
this.tblTest.Text = state as string;
}
}
}
I use the HttpWebRequest async methods to retrieve the resource from the server and set the Text of my TextBlock to the resource content. I handle the possible exceptions and if an exception occurs the text will contain the exception message. Also if the server returns status different from OK the text will contain the status code.
I tested my example with Fiddler to see if some cookies would be sent to the server. Only when the user was authenticated a cookie named “Login” was sent. Additionally my TextBlock showed the expected result.
Note that this will work only if your site membership system is cookie driven.
Your resource can be a web service or whatever you want.
Conclusion
This article focuses on the fact that you do not need to make login system both on your site and the Silverlight application when your site uses cookies for its authentication. Any comments are welcome.
Reference
I recommend you to read this article by Karen Corby where she explains the vulnerabilities that may originate from using cookie driven authentication and cross – domain requests from your Silverlight application.
http://scorbs.com/2008/04/22/silverlight-http-networking-stack-part-3-configuring-a-cross-domain-policy-file/
Since I did not make cross-domain requests in my example these things don’t bother me.