Sharing ASP Session state with Silverlight
I’ve been working on a Silverlight project that where the SL application is used within an authenticated ASP.net site. During my testing I found a problem where using Silverlight 3’s Out-Of-Browser feature seem to lose the session token between calls to the site, i.e. I could logon but the next call would fail as if the user had not logged on. After a couple of Twitter conversations it became apparent that it should work. So I decided to take my testing back to basics, so first off can a Silverlight application use ASP session state?
-
Create a basic Silverlight application – create a Silverlight application with a web project to host it
-
Create a basic web service – with the web project selected add a new Silverlight WCF service, called SessionTest.svc
-
Implement some very simple interactions with the Session State
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class SessionTest
{
[OperationContract]
public void SetState(string value)
{
// Add your operation implementation here
HttpContext.Current.Session["TestState"] = value;
return;
}
[OperationContract]
public string GetState()
{
// Add your operation implementation here
return (string)HttpContext.Current.Session["TestState"];
}
}
-
Add a Service Reference from your Silverlight application to your service, add appropriate using statements to your code-behind.
-
Create some simple controls in your Silverlight application
<StackPanel>
<StackPanel Orientation="Horizontal">
<Button x:Name="ButtonGetState" Content="Get State" Click="ButtonGetState_Click" Width="60" ></Button>
<TextBlock x:Name="TextBlockCurrentState" Width="100"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox x:Name="TextBoxNewState" Text="" Width="100"></TextBox>
<Button x:Name="ButtonSetState" Content="Set State" Click="ButtonSetState_Click" Width="60"></Button>
</StackPanel>
</StackPanel>
-
Add code to the Silverlight application to communicate with the Service
private void ButtonGetState_Click(object sender, RoutedEventArgs e)
{
SessionTestClient client = new SessionTestClient();
client.GetStateCompleted += (object completedSender, GetStateCompletedEventArgs completedE) =>
{
if (completedE.Error == null)
{
TextBlockCurrentState.Text = completedE.Result;
}
};
client.GetStateAsync();
}
private void ButtonSetState_Click(object sender, RoutedEventArgs e)
{
SessionTestClient client = new SessionTestClient();
client.SetStateCompleted += (object completedSender, AsyncCompletedEventArgs completedE) =>
{
if (completedE.Error == null)
{
TextBlockCurrentState.Text = "";
}
};
client.SetStateAsync(TextBoxNewState.Text);
}
-
Run the code, you should see that after you set a value you can retrieve the same value.
So we now know for sure that we can communicate with ASP.net and share the session state with the page. If you make the Silverlight application OOB (select project properties and check the OOB box) you’ll see that it continues to work without any problems. So this is good news, all I have to do now is track down why it isn’t working in my real application.
Remote debugging – value as being optimized
Listing the files in a Changeset
C:\Program Files\Microsoft Visual Studio 8\Common7\IDE>tf changeset /i 27880
Passing Exceptions from WCF to Silverlight
Database for Silverlight
Another quick bookmark of a blog that talks about an open source database project that could be ideal for Silverlight out-of-browser applications
Online Visual Studio like IDE
Linq recipe #3, flatten a dictionary of byte arrays into a single byte array
Dictionary<int, byte[]> binaryParts = new Dictionary<int, byte[]>();
…
// now combine the binary from all the parts by first sorting by key
var flattenedList = binaryParts.OrderBy(p => p.Key).SelectMany(p => p.Value);
byte[] combinedBytes = flattenedList.ToArray();
Linq recipe #2, Convert a CSV string of numbers into an array of numbers
e.g. for every (n) item in the array, apply the Convert function to it and return that as the nth item in the new array
int[] strongValues = Array.ConvertAll(csvString.Split(‘,’), n => Convert.ToInt32(n));
Linq recipe #1 combining two enums into a single dictionary
// Using Linq, ignore problems with jaggies
List<int> keys = new List<int> { 1, 2, 3, 4, 5 };
List<string> data = new List<string> { "a", "b", "c", "d","e" };
Dictionary<int,string> combo = (from k in keys
join d in data on keys.FindIndex(x => x==k) equals data.FindIndex(x2 => x2==d)
select new {Key=k, Value=d} ).ToDictionary(de=>de.Key, de=>de.Value);
foreach (var i in combo)
{
System.Diagnostics.Debug.WriteLine(i.Key + "," + i.Value);
}
// Using lamda expression, doesn’t allow jaggies
Dictionary<int, string> UrisByProject = new Dictionary<int, string>();
List<int> nonZeroProjectIds = new List<int>() { 1, 2, 3, 4,5 };
List<string> urisForTheImage = new List<string>() { "a", "b", "c", "d", "e" };
nonZeroProjectIds.ForEach(p => UrisByProject.Add(p, urisForTheImage[nonZeroProjectIds.FindIndex(t => t == p)]));
foreach (var i2 in UrisByProject)
{
System.Diagnostics.Debug.WriteLine(i2.Key + "," + i2.Value);
}