Tuesday, January 20, 2009

Silverlight 2 : Maintain data in Session using Silverlight-enabled WCF service.

A piece of paper was thrown in front of me on table by my friend in local coffee shop, that paper was nothing but print out of one already designed ASP.NET site which now he want to convert to Silverlight with few of pages as kind of POC for Silverlight. I just saw “Welcome : <Username>” label on that, and I asked him how he is taking care of Sessions in Silverlight? and a puzzle for him..since he never implemented, there are several solutions on net by many people and enthus, here is my piece of code which I feel simple, offcourse you can try that out and help me improve if there any better way to do so.

To show this particular functionality, I am re-using my old code of Master pages in Silverlight since I need more than one page with navigation which you can find it here :

http://pendsevikram.blogspot.com/2008/11/silverlight-2-master-pages.html

Also, if you are not comfortable with Silverlight-enabled WCF services , you can see my old article :

http://pendsevikram.blogspot.com/2008/10/silverlight-2-grid-with-silverlight.html

Step 1 : Create 2 Silverlight Pages

Page.xaml :

<Grid x:Name="LayoutRoot" Background="AliceBlue">
        <TextBlock Height="23" Margin="94,8,116,0" VerticalAlignment="Top" Text="Explore .NET with Vikram Pendse" TextWrapping="Wrap" Foreground="#FF000000"/>
        <StackPanel x:Name="stk" Width="400" Margin="0,66,0,30">
            <TextBlock Margin="78,10,0,30" Text="UserName:"/>
            <TextBox Margin="40,-50,0,30" x:Name="txtuser" Height="20" Width="150" />

<TextBlock Margin="78,-5,25,30">Password :</TextBlock>
            <PasswordBox Margin="40,-60,0,10" x:Name="txtpassword" Height="20" Width="150" />
            <Button x:Name="btnSubmit" Height="20" Width="100" Content="Login" Click="btnSubmit_Click" />
        </StackPanel>
        <TextBlock Height="23" Margin="106,0,104,3" VerticalAlignment="Bottom" Text="Microsoft .NET for everyone!!" TextWrapping="Wrap" Foreground="#FF000000"/>
</Grid>

Welcome.xaml :

<Grid x:Name="LayoutRoot" Background="AliceBlue">
        <StackPanel x:Name="mystk" Width="400" Margin="0,66,0,30">
            <TextBlock Margin="128,-5,0,30" Text="Welcome :"/>
            <TextBlock Margin="196,-46,0,30" x:Name="txtusername" />
        </StackPanel>     
</Grid>

Step 2 : Add a Silverlight-enabled WCF Service and access it in Silverlight application

MyService.svc.cs :

using System.Web;

[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class MyService
    {
        HttpContext myctxt = HttpContext.Current;

        [OperationContract]
        public string Login(string username, string password)
        {
            //Validate Username and Password against the Database.
            myctxt.Session["Uname"] = username;
            return username;
        }

        [OperationContract]
        public string ReturnUser()
        {
            string user;
            user = (string)myctxt.Session["Uname"];
            return user;
        }

Note : For demo purpose, I have not validated User-id and Password against database, please refer comment.

Step 3 : Consume SL-enabled WCF service in each page and pass the corresponding parameters.

First we need to send username and password from Page.xaml.cs to Service, Then Login() will maintain that particular username in session, Then we will again call the service and access that particular username which is in session by ReturnUser()

Page.xaml.cs :

private void NavigateRequest(int w)
{
     if (w > 0)
     {
         stk.Children.Clear(); 
         stk.Children.Add(new Welcome());
      }
      else
      {
          this.Content = new Page();
      }            
}

private void btnSubmit_Click(object sender, RoutedEventArgs e)
{
    Srvc.MyServiceClient proxy = new SL_SessionMgmt.Srvc.MyServiceClient();
    proxy.LoginAsync(txtuser.Text,txtpassword.Password);
    NavigateRequest(1);
}                

Here we are switching among the pages by NavigateRequest(), you can write Switch-case if there are multiple pages.

Welcome.xaml.cs :

public Welcome()
{
    InitializeComponent();
    this.Loaded += new RoutedEventHandler(Welcome_Loaded);
}

void Welcome_Loaded(object sender, RoutedEventArgs e)
{
     Srvc.MyServiceClient proxy = new SL_SessionMgmt.Srvc.MyServiceClient();
     proxy.ReturnUserCompleted += new EventHandler<SL_SessionMgmt.Srvc.ReturnUserCompletedEventArgs>(proxy_ReturnUserCompleted);
     proxy.ReturnUserAsync();
}

void proxy_ReturnUserCompleted(object sender, SL_SessionMgmt.Srvc.ReturnUserCompletedEventArgs e)
{
      txtusername.Text = e.Result;
}

And here we are getting username which is in session by e.Result, This will display the username in session on Textblock on second page, it will look like this.

SLSession1

Here you can see whatever we pass as username, we place it in session by WCF service and get that data from session via service again and bind it to another control on another page.

SLSession2

Hope this will useful for you, if you are planning to implement Sessions in your Silverlight applications.

Vikram. 

14 comments:

Aditya Kanekar said...

Hi Vikram,

I tried this code but i m not getting the current http context.

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class HVService : IHVService
{
HttpContext serviceContext = HttpContext.Current;


}

Vikram Pendse said...

Hello Aditya,

I assume that you incorporating "System.Web" namespace,beside that let me agian verify the code and will get back to you soon.

Vikram Pendse said...

Hi Aditya,

I rechecked that and its working perfect here, even after re-running for several times, I even created another dummy project with same code, no issues in that also, let me know if you still have any issues.

Daniel said...

You're probably missing this one Aditya:
System.ServiceModel.Activation;

Nur 'Ain Abd. Rahim said...

hi there, can u explain to me on regards to linking the username and password from the database for it to work?

Dev said...

Would be nice to have a sample to test.
I get an error on: Srvc.ServiceSessionTestClient proxy = new Srvc.ServiceSessionTestClient();

System.Collections.Generic.KeyNotFoundException was unhandled by user code
Message="The given key was not present in the dictionary."
...

Everything compiled ok.

Vikram Pendse said...

@ Nur 'Ain Abd. Rahim : You can do authentication with UserId and Password from Database or against it, provided you have that Operation Contract written by yourself which will have a connection object which connects to Database and fetch authentication information using command object, Then you can match with the UserID and Password provided from UI

@ Dev : I assume that you hosted your service accurately, However I tired the same code and tested on few other environments,it do work well.

Durga Prasad said...

Hi Vikram can you send me the source code for this article

Durga Prasad said...

Hi Vikram can u please send me the source code of this article

Roger said...

Session is allways null for me, is there something that is off by default with a Silverlight Business Application, that is on with a normal ASP.net app?

Satish said...

i have codded as you explained me but i am not getting the username in welcome page,even i am not getting any error also,what's wrong in the code i dont understand,can you please help me at babu_dpl@yahoo.com

Abir.jmaiel said...

that' great it helped me thank you

Shiv said...

Session is allways null for me
in maintain session using silverlight enabled wcf service.
tell me the missing thing

divya said...

hi vikram...
i did the same way u did but unable to get username in next page...could u help me out...

trying to learn silverlight