Using ASP.NET Sessions from WCF


This is not a new topic. But interestingly I could not find a good example on the web while I wanted to find one for some other investigation. So I decided to create a sample here to show the following scenario:


·        A WCF service has the access to a ASP.NET session. Different WCF client proxies can connect to the per-call WCF service and share the same ASP.NET session state.


Here I will show a simple example on how to achieve this.


ASP.NET Sessions vs WCF Sessions


WCF sessions are very different from ASP.NET Sessions. In short,


·        WCF sessions are represented as service instances (as CLR objects) and the states are part of each service instance. The sessions are initiated by the calling WCF client. WCF relies on special context to provide correlation for the sessions: sessionful channels, secure conversations, reliable-messaging, etc.


·        ASP.NET sessions are like shared data storage across different requests. The sessions are always initiated by the server. ASP.NET relies on cookies or special Uri goo to provide correlation for the sessions.


You can find more details for the comparisons of the two from the MSDN article “Using Sessions”.


While these two concepts are quite different and the usages are also drastically different, the WCF sample “HttpCookieSession” tried to use the similar idea as cookie-based ASP.NET sessions to provide WCF session support. The sample is a little bit complex and it does not use real ASP.NET sessions though.


There are many samples on how to use WCF sessions, for example, “How to: Create a Service That Requires Sessions” is a good one.


So I will only show how to use ASP.NET sessions from WCF below. It uses PerCall service to handle this. So different service instances have access to the same ASP.NET session state.


Using ASP.NET Session States


Storing Session States


It is known that ASP.NET session states can be stored in different places: 1) In-Memory (thus In-process), 2) Out-of-proc state service, 3) SQL server, 4) a custom session-state store provider, etc. More details can be found in “ASP.NET Session State Overview”.


For simplicity, I will just show the in-memory case. Here is a very simple session state:


class MySessionState


{


    int counter;


    public MySessionState() {}


    public int Counter { get { return this.counter; } }


    public int Touch() { return Interlocked.Increment(ref this.counter); }


}


 


The state just contains a single counter. This state is stored in the session object as following:


MySessionState state = (MySessionState)HttpContext.Current.Session[“MySessionState”];


if (state == null) {


    state = new MySessionState();


    HttpContext.Current.Session[“MySessionState”] = state;


}


 


When the service receives a request, the sample increments the counter to demonstrate the sharing effect:


int counter = state.Touch();


Enabling Session States


It is very straightforward to enable the ASP.NET session states. You only need to run WCF service in the ASP.NET Compatibility mode as being specified in the web.config:


<serviceHostingEnvironment aspNetCompatibilityEnabled=true/>


Retrieving Session Id on the Client


Once the session states are enabled and there is session data populated as above, we can retrieve the Session Id from the cookie on the client side:


using (new OperationContextScope((IContextChannel)proxy))


{


    Console.WriteLine(proxy.Greet(“Hello”));


    HttpResponseMessageProperty responseProperty = OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name]


        as HttpResponseMessageProperty;


    helper = HttpSessionCookieHelper.Create((string)responseProperty.Headers[HttpResponseHeader.SetCookie]);


}


 


Here the type “HttpSessionCookieHelper” is just a helper class that is used to retrieve the ASP.NET Session Id from the cookie string (with the cookie name “ASP.NET_SessionId”) and append the Session Id to the request. It is defined as following:


class HttpSessionCookieHelper


{


    const string AspNetSessionIdCookieName = “ASP.NET_SessionId”;


    string aspNetSessionId;


    public static HttpSessionCookieHelper Create(string cookieString);


    public static HttpSessionCookieHelper CreateFromSessionId(string sessionId);


    public void AddSessionIdToRequest(HttpRequestMessageProperty requestProperty);


    public string AspNetSessionId { get { return this.aspNetSessionId; }


}


Sending Session Id


Once we get the Session Id retrieved from the response of the first request, we can share it for the subsequent client calls. Here is the example:


using (new OperationContextScope((IContextChannel)proxy))


{


    HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty();


    helper.AddSessionIdToRequest(requestProperty);


    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;


    Console.WriteLine(proxy.Greet(“Howdy”));


}


The implementation of the HttpSessionCookieHelper.AddSessionIdToRequest does nothing but the following:


requestProperty.Headers[HttpRequestHeader.Cookie] = string.Format(“{0}={1}”, AspNetSessionIdCookieName, this.aspNetSessionId);


 


With this logic, the second request would share the same ASP.NET Session State on the server side.


Sample Setup


Here are the steps on how to use it:


1)     Unzip the attachment locally.


2)     Create a virtual application with name “WCFAspNetSession” and the physical path points to the “WCFAspNetSession” directory.


3)     Compile the client code and run it.


 


Here is the output of the sample:


[Session ‘1vgfq255e1lpe255whwprf55’] You said: Hello (counter: 1)


[Session ‘1vgfq255e1lpe255whwprf55’] You said: Howdy (counter: 2)


As you can see, the Session Ids for the two requests are the same and the counter for the shared state has increased.


 


Here is the sample code: [sample attachment].

WCFAspNetSession.zip

Comments (5)

  1. Niels Bos says:

    You are the MAN!!! Thank you so much! This was taking forever and I really was in dire straights for this solution.

    Cheers!

  2. juan alvarez says:

    me parece muy  buen articulo, me gustaria si pudieras publicar uno en VB, te lo agradeceria mucho

  3. Ido Flatow says:

    When using ASP.NET sessions with WCF, there is a concurrency problem which can cause requests to be synchronized:

    blogs.microsoft.co.il/…/asp-net-compatible-wcf-services-concurrency-problem.aspx

  4. urig says:

    Thank you for this elaborate demo. I downloaded the zip and your sample ran without a glitch.

    I have a question – I've tweaked the sample so as to have each of the two channels created by a different channel factory. I've simply duplicated the channel factory and used the duplicate to create the second channel (in Inoke2()). When I do this, the server no longer recognizes that both channels share the asp.net session. Fiddler shows me that the second channel does not include the cookie in its request to the server.

    Any idea why this is happening? Why would the sample work when both channels come from the same factory and fail when they come from different factories?

    Many thanks,

    urig

  5. Michael freidgeim says:

        The line

    .OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;

    Didn't work for us. we've changed to

        .OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name,requestProperty);