我们使用 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 操作完成,它将被释放。如果需要,您可以按正常方式使用事务。