开发者

WCF/S#arpArch: underlying ISession is closed after the first call within a request

开发者 https://www.devze.com 2022-12-22 08:28 出处:网络
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.

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 th开发者_开发问答rows an ObjectDisposedException: "Session is closed! Object name: 'ISession'".

Any ideas?


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号