WPF: Inconsistent SessionID when using web services

.NET, Technical stuff, WPF
See comments
You got to love the internet. Minutes after I wrote about what I thought was a bug in WPF, Joseph Cooney pointed me to this page which explains how to save the cookie on the client to avoid losing the SessionID. Seems that I have been spoilt by my years of ASP.NET programming, where the browser stores the cookies automatically. I will update the example, and will post again about this soon!
Problem
This prototype demonstrates that, in WPF, the SessionID used when calling web services is not saved by default.
Using SessionID in web services
When a client calls a web service the first time, it is assigned a unique identifier called SessionID, which is saved using cookies. When the following calls arrive, the SessionID is read from the cookies collection, and the Session object (HttpSessionState) is retrieved. This object can be used to store state information related with the calling client.
In order to make the Session object accessible to web methods, the "WebMethod" attribute decorating the web method uses the EnableSession attribute, which must be set to true.
[WebService( Namespace = "http://www.galasoft-lb.ch/" )]
[WebServiceBinding( ConformsTo = WsiProfiles.BasicProfile1_1 )]
[ToolboxItem( false )]
public class Service1 : System.Web.Services.WebService
{
  [WebMethod( EnableSession=true )]
  public string GetSessionId()
  {
    return Session.SessionID;
  }
}
Web method accessing the Session
Using web services in WPF
Windows Presentation Foundation (WPF) can consume ASMX web services easily, because they relay on the .NET framework. In .NET 2.0, using a web service is as easy as adding a Web Reference to the project (Right-click on the project / Add Web Reference...). Enter the URL of the ASMX file, and select the service you want to use.
Once this is done, the web service is available as a proxy, meaning that calling a method on the proxy object will automatically send the web service request, wait for the answer and parse the response, providing the client with the corresponding result.
Web methods can be called synchronously and asynchronously, but the async mode is better, because it doesn't block the client while the request is sent and processed. The client simply registers a method to the "Completed" event of the corresponding method. In Visual Studio 2005, this is very easy to do: Select the "Completed" event you want to register with, then type "+=". This presents you with a dialog asking if you want Studio to insert the corresponding code. Press "Tab" to confirm, and then "Tab" again to declare the method.
private void bnGetSessionId_Click( object sender, RoutedEventArgs e )
{
  try
  {
    GetSessionIdService.Service1 oSessionIdService
      = new GetSessionIdService.Service1();
    oSessionIdService.GetSessionIdCompleted
      += new GetSessionIdService.GetSessionIdCompletedEventHandler(
        oSessionIdService_GetSessionIdCompleted );
        oSessionIdService.GetSessionIdAsync();
  }
  catch ( Exception ex )
  {
    lblSessionId.Text = ex.Message;
    lblSessionId.Foreground = Brushes.Red;
  }
}
Calling the wen method asynchronously
The only step remaining now it to handle the response, in the corresponding event handler.
private void oSessionIdService_GetSessionIdCompleted( object sender,
  GetSessionIdService.GetSessionIdCompletedEventArgs e )
{
  if ( e != null
    && e.Result != null
    && e.Result.Length > 0 )
  {
    if ( lblSessionId.Text.Length > 0 )
    {
      lblSessionId.Text += Environment.NewLine;
    }
    lblSessionId.Text += "SessionID at "
      + DateTime.Now.ToLongTimeString()
      + ": " + e.Result;
    lblSessionId.Foreground = Brushes.Black;
  }
  else
  {
    lblSessionId.Text = "Unknown error";
    lblSessionId.Foreground = Brushes.Red;
  }
}
Processing the Response
Consequences
Many web services use the Session object to store state information. Most web application nowadays are stateful to enable a better user experience. It is therefore necessary to save the SessionID on the WPF client when using web services, or else on every request, a new Session object is created. My prototype demonstrates the fact: Every time you call the service, it returns a different session ID.
In order to save the SessionID in a cookie on the client, a CookieContainer must be used. This page at MSDN shows how.
Previous entry | Next blog entry

Responses to “WPF: Inconsistent SessionID when using web services”

  1. Joseph Cooney Says:

    I was not able to download the code (I got a 404) but I think you need to assign a cookie container to the client proxy if you want to retain the session cookie between requests. This is described (poorly) here http://msdn2.microsoft.com/en-us/library/system.web.services.protocols.httpwebclientprotocol.cookiecontainer.aspx

  2. Laurent Says:

    Sorry for the 404, this is corrected now.

    I will check the link you gave me and try again. Thanks!

  3. Ian Griffiths Says:

    Maybe I'm missing something, but I don't see what this has to do with WPF?

    The issue you describe here is entirely to do with web service proxies that are generated for you when you use the Add Web Reference feature of Visual Studio. That's not a WPF feature - it works the same way whether you use it from WPF, Windows Forms, an ASP.NET app, a console app, or anything else.

    So you'd have to use a cookie container to ensure that cookies are remembered if you were using any of these other technologies as the client. (Even ASP.NET - it may be a web technology, so you might think it's cookie aware, but actually, as far as I know when it's acting as a web service *client* it doesn't remember cookies unless you provide a container.)

    I don't see anything in this web page that is specific to WPF. (Other than the fact that you happened to be writing a WPF app when you ran into this non-WPF-specific issue.) Have I missed something?

  4. Laurent Says:

    Ian,

    You are totally right. When I wrote this, I thought that this was a WPF issue, because in our study of the technology, we encountered many places where the technology was unfinished, and some features were unavailable. Hence the confusion.

    Since then I wrote a follow up available here
    http://geekswithblogs.net/lbugnion/archive/2006/10/11/93743.aspx

    You are exactly right that the technology used here is not WPF-only, but also applies to Windows Forms.

    Greetings
    Laurent

Comments for WPF: Inconsistent SessionID when using web services