WCF / S#arpArch:在请求中的第一次调用之后,底层ISession将关闭

我知道在SA中使用WCF已被弃用,因为它将转移到SA Contrib。 但是直到它有,我想我必须使用SA中的支持。

也就是说,我在调用WCF服务后关闭了底层的NHibernate会话。 我的存储库的DbContext.Session在第一次调用后关闭,因此在单个HTTP请求期间我不能多次调用我的服务。

我基于Northwind示例应用程序在我的项目中设置了WCF。 该示例仅在每个请求中调用一次WCF服务,因此此问题不会显示在那里。 但是,通过复制TerritoriesController中的以下行,可以轻松复制该问题:

territories = territoriesWcfService.GetTerritories();

这会抛出一个ObjectDisposedException:“Session is closed!Object name:’ISession’”。

有任何想法吗?

我设法解决了它。

通过检查SharpArch.Wcf源代码,我发现在发送WCF服务响应之前,它总是关闭所有NHibernate会话。 这本身就是一件好事。

另外,我发现我的客户端代理工厂每个Web请求只触发一次,而第二个服务调用应该引发一个新的代理实例。 结果是第二个服务调用将失败,因为基础NHibernate会话已经关闭。 我通过使用Castle.Core.TransientAttribute来装饰我的客户端代理类,从而将生命周期管理留给创建客户端的工厂。 结果是每次请求代理时都会调用我们的代理工厂。

其次,我必须像这样注册代理(在ComponentRegistrar类中):

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

WcfSessionFacility管理客户端的关闭/中止,具体取决于其状态。 这样可以确保每当客户端代理被销毁时客户端通道都会关闭,因此我们不需要将调用放在try-catch块中。

像我一样,您可能会考虑在添加组件时配置生命周期管理而不是使用属性,但显然没有合适的AddComponentWithExtendedProperties重载允许这样做。

我对SharpArchitecture并不熟悉,但看起来你在这里至少有两个选择:

  1. 在客户端,在第一次调用之后处置WCF服务,并在进行第二次调用之前新建另一个WCF服务,从而获得新的ISession。

  2. 使WCF服务更智能地处理会话,以便您可以更长时间地打开会话。 有多种方法可以做到这一点,它可能涉及WCF服务中相当数量的新逻辑,但它应该是完全可行的。