WCF/S#arpArch: underlying ISession is closed after

2019-02-11 09:36发布

I know the use of WCF in SA is deprecated because it will move to SA Contrib. But until it has, I guess I have to use the support in SA.

That said, I have a problem with the underlying NHibernate session being closed after calling a WCF service. My repository's DbContext.Session is closed after the first call so I cannot call my service more than once during a single HTTP request.

I've set up WCF in my project based on the Northwind sample application. The sample only calls a WCF service once per request so this problem doesn't show up there. The problem is easily reproduced though, by duplicating the following line in the TerritoriesController:

territories = territoriesWcfService.GetTerritories();

This throws an ObjectDisposedException: "Session is closed! Object name: 'ISession'".

Any ideas?

2条回答
我只想做你的唯一
2楼-- · 2019-02-11 10:20

I managed to solve it.

By inspecting the SharpArch.Wcf source code, I found that before the WCF service response is sent, it always closes all NHibernate sessions. This in its 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. 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):

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.

查看更多
贼婆χ
3楼-- · 2019-02-11 10:26

I'm not that familiar with SharpArchitecture, but it seems like you have at least two options here:

  1. On the client side, dispose the WCF Service after the first call and new up another WCF Service before making the second call, thus getting a new ISession.

  2. Make the WCF Service smarter about session disposal such that you can keep the session open longer. There are multiple ways to do this and it probably involves a decent amount of new logic in the WCF service, but it should be totally feasible.

查看更多
登录 后发表回答