S#arpArchitecture, WCF and session lifetime

by sandord 4. maart 2010 14:23

I've recently started a new project using S#arpArchitecture and WCF. Currently, there is some support in S#arpArch for WCF but it is deprecated until the S#arp Architecture Contrib project takes it over. That hasn't happened yet but still I'm confident it's a solid enough solution to use WCF with S#arpArch now. Since it's open source, fixing problems should not be too hard anyway.

Problem

Ofcourse, I ran into a problem quite soon. I had based my implementation on the NorthwindSample application, which is supplied with S#arpArch. Ofcourse the sample ran just fine until I tried to do something different, the usual thing. In my case, I couldn't call a service twice within the same web request. It appeared that the underlying NHibernate session got closed right after calling a WCF service.

The problem is easily reproduced by duplicating the following line in the TerritoriesController of the sample application:

territories = territoriesWcfService.GetTerritories();

This throws an ObjectDisposedException: "Session is closed! Object name: 'ISession'". After inspecting the SharpArch.Wcf source code, I found that before the WCF service response is sent, it always closes all NHibernate sessions. This in it self is a good thing.

In addition, I found that my client proxy factories only fired once per web request, while the second service call should induce a new proxy instance. The result was that the second service call would fail because the underlying NHibernate session was closed already.

Solution

I solved that by decorating my client proxy classes with the Castle.Core.TransientAttribute, which leaves the lifetime management up to the factory that creates the client. The result of that is that our proxy factories get called every time a proxy is requested.

Second, I had to register the proxies like this (in the ComponentRegistrar class):

string zipCode = string.Empty;
container.AddFacility("WcfSessionFacility", new WcfSessionFacility());

container.Kernel.AddComponentWithExtendedProperties(
    "AccountService",
    typeof(IAccountService),
    typeof(AccountServiceClient),
    new Dictionary<string, object>()
        {
            { WcfSessionFacility.ManageWcfSessionsKey, true }
        });

The WcfSessionFacility manages closing/aborting of the client, depending on its state. This makes sure the client channel is closed whenever the client proxy is destroyed so we don't need to put our calls in try-catch blocks.

Like me, you might think to configure lifetime management while adding the component instead of using an attribute but apparently there is no suitable overload of AddComponentWithExtendedProperties that allows this.

Tags: ,

About the author

My name is Sandor Drieënhuizen and I'm a passionate and self employed .NET oriented developer, piano player and seeker of the non-obviousness.

Month List