所以我的猜测是:
使用WCF进行Hibernate会话管理的任何建议(最佳实践)?
任何人都知道
WcfOperationSessionContext (hibernate 3.0)类?
how to use it with WCF?
好吧,让它具体化:
假设我有名为 DataServices
的WCF服务class WCFDataService .....
{
void SaveMyEntity(MyEntity entity)
{
.....................?? // How to do? Best Way
// Should i take one session and use it all times
// Should i take session and dipsose when operation finished then get
//new session for new operations?
// If many clients call my WCF service function at the same time?
// what may go wrong?
// etc....
}
}
我需要一个 NHibernateServiceProvider 类
class NHibernateServiceProvider ....
{
// How to get Session ?? Best way
ISession GetCurrentSession(){.... }
DisposeSession(){ ....}
}
祝福
PS:我在这里和其他网页上都读过类似的条目。但看不出“具体”的答案。
答案 0 :(得分:9)
WcfOperationSessionContext类似于ThreadStaticSessionContext和WebRequestSessionContext是会话上下文的实现。会话上下文用于将ISession实例绑定(关联)到特定上下文。
可以通过调用ISessionFactory.GetCurrentSession()来检索当前上下文中的会话。
您可以找到有关session context here。
的更多信息WcfOperationSessionContext表示跨越WCF操作的整个持续时间的上下文。您仍然需要在操作开始时处理会话的绑定,并在操作结束时处理会话的解除绑定/提交/处理。
要访问wcf管道中的开始/结束操作,您需要实现IDispatchMessageInspector。您可以看到示例here。
关于WCF集成:如果你使用ThreadStatic会话上下文,它似乎可以在开发上工作,但是当wcf管道中的各种组件(例如:授权,身份验证)在不同的线程上执行时,你将在生产中遇到问题。
至于你几乎把它钉在最佳实践上:使用WcfOperationSessionContext存储当前会话和IDispatchMessageInspector来开始/完成你的工作单元。
编辑 - 解决您添加的详细信息: 如果您配置了WcfOperationSessionContext并按照上面的说明进行绑定/解除绑定,那么您所要做的就是将ISessionFactory注入您的服务并使用factory.GetCurrentSession()。如果时间允许,我会发布一个样本prj。
答案 1 :(得分:5)
我们用于管理与WCF的NHibernate会话的模型如下:
1)我们有自己的ServiceHost类,它继承自System.ServiceModel.ServiceHost,它也实现了ICallContextInitializer。我们将服务主机实例添加到我们服务中的每个操作中,如下所示:
protected override void InitializeRuntime()
{
base.InitializeRuntime();
foreach (ChannelDispatcher cd in this.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
foreach (DispatchOperation op in ed.DispatchRuntime.Operations)
{
op.CallContextInitializers.Add(this);
}
}
}
}
public void AfterInvoke(object correlationState)
{
// We don't do anything after the invoke
}
public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
OperationContext.Current.Extensions.Add(new SessionOperationContext());
return null;
}
BeforeInvoke只是确保每个WCF调用的OperationContext都有自己的会话。我们发现IDispatchMessageInspector存在问题,其中会话在响应序列化期间不可用 - 如果使用延迟加载则会出现问题。
2)然后我们的SessionOperationContext将被调用以附加自身,我们使用OperationCompleted事件来移除自己。这样我们就可以确保会话可用于响应序列化。
public class SessionOperationContext : IExtension<OperationContext>
{
public ISession Session { get; private set; }
public static SessionOperationContext Current
{
get
{
OperationContext oc = OperationContext.Current;
if (oc == null) throw new InvalidOperationException("Must be in an operation context.");
return oc.Extensions.Find<SessionOperationContext>();
}
}
public void Attach(OperationContext owner)
{
// Create the session and do anything else you required
this.Session = ... // Whatever instantiation method you use
// Hook into the OperationCompleted event which will be raised
// after the operation has completed and the response serialised.
owner.OperationCompleted += new EventHandler(OperationCompleted);
}
void OperationCompleted(object sender, EventArgs e)
{
// Tell WCF this extension is done
((OperationContext)sender).Extensions.Remove(this);
}
public void Detach(OperationContext owner)
{
// Close our session, do any cleanup, even auto commit
// transactions if required.
this.Session.Dispose();
this.Session = null;
}
}
我们在高负载应用程序中成功使用了上述模式,它似乎运行良好。
总之,这类似于新的WcfOperationSessionContext所做的(当我们弄清楚上面的模式时,它不在我们身边;-))但也克服了延迟加载的问题。
关于提出的其他问题:如果您使用上述模型,则只需执行以下操作:
void SaveMyEntity(MyEntity entity)
{
SessionOperationContext.Current.Session.Save(entity);
}
您可以保证会话始终存在,并且一旦WCF操作完成,它将被丢弃。如果需要,您可以以正常方式使用交易。
答案 2 :(得分:3)
这是一个post,详细描述了注册和使用WcfOperationSessionContext的所有步骤。它还包括将其与agatha-rrsl项目一起使用的说明。
答案 3 :(得分:1)
好的,在阅读互联网帖子等几天后,互联网中显示的所有方法似乎都是错误的。当我们使用带有nhibernate事务的NH 3 ^的UnitOfWork模式时,所有的aprochaes都会产生异常。为了测试它并证明我们需要使用MSMQ事务队列创建测试环境,需要在其上设置具有事务所需的OneWay操作契约的特殊接口。这种方法应该是这样的: 我们将事务性消息放入队列中。 2.服务从队列中获取事务消息。 所有工作队列都是空的。
在某些情况下,对互联网方法不太满意,这种方式无法正常运行。所以这里是我们测试的示例,这是错误的,为什么:
解决方案是什么?
IOperationInvoker ,只有这个!
您需要在默认调用者上将此接口实现为装饰器模式。在调用之前的方法调用中,我们打开会话/事务打开然后我们调用invoke默认调用者,然后在最后的clausule中调用transaction.complete,我们调用session.flush。这解决了什么类型的问题: 1.我们在此级别上有事务范围,因此当完成抛出异常消息将返回队列并且WCF不会关闭。 2.当调用时会抛出异常transaction.complete将不会被调用什么不会改变数据库状态
我希望这能清除每个人的错误信息。
在一些空闲时间里,我会尝试写一些例子。