C# 优化:使用PerSession InstanceContext实现WCF的Castle ActiveRecord会话范围
为了方便在使用AR的WCF服务上进行延迟加载,我为WCF创建了一个会话范围PerRequest解决方案 如果您想在网站或web服务中使用ActiveRecord,您必须通过它在web环境中运行的配置告诉它 无论它如何假设它将具有WCF中不存在的HttpContext.Current 因此,我们告诉AR使用我们自己的AbstractThreadScopeInfo实现,它也实现了IWebThreadScopeInfo,告诉AR它与每个请求的会话模式兼容,该模式现在变成了每个会话的会话模式 为我从中遇到的延迟加载异常添加了一些修复 如上所示,我们需要一个WCFStackContainer,它可以添加到当前的OperationContext.Extensions中。为了促进这一点,需要实现IExtension。请看这里:C# 优化:使用PerSession InstanceContext实现WCF的Castle ActiveRecord会话范围,c#,wcf,nhibernate,castle-activerecord,C#,Wcf,Nhibernate,Castle Activerecord,为了方便在使用AR的WCF服务上进行延迟加载,我为WCF创建了一个会话范围PerRequest解决方案 如果您想在网站或web服务中使用ActiveRecord,您必须通过它在web环境中运行的配置告诉它 无论它如何假设它将具有WCF中不存在的HttpContext.Current 因此,我们告诉AR使用我们自己的AbstractThreadScopeInfo实现,它也实现了IWebThreadScopeInfo,告诉AR它与每个请求的会话模式兼容,该模式现在变成了每个会话的会话模式 为我从中遇
public class WCFStackContainer : IExtension<OperationContext>
{
private Stack _stack;
public Stack Stack
{
get { return _stack; }
set { _stack = value; }
}
#region Implementation of IExtension<OperationContext>
public void Attach (OperationContext owner)
{
//On Attachment to the OperationContext create a new stack.
_stack = new Stack();
}
public void Detach (OperationContext owner)
{
_stack = null;
}
#endregion
}
这无法在WCF中完成,因此您需要以下内容:
public class ARSessionWCFExtension : IExtension<OperationContext>
{
private static readonly ILog Logger = LogManager.GetLogger (typeof(ARSessionWCFExtention));
private SessionScope _session;
#region IExtension<OperationContext> Members
public void Attach (OperationContext owner)
{
Logger.Debug ("Attachig ARSessionScope to WCFSession");
_session = new SessionScope();
}
public void Detach (OperationContext owner)
{
try
{
Logger.Debug ("Detaching ARSessionScope from WCFSession");
if (_session != null)
_session.Dispose ();
}
catch(Exception ex)
{
Logger.Fatal ("Exception: " + ex.Message + " Stacktrace: " + ex.StackTrace);
}
}
#endregion
}
在IDisposable实现中,我们添加了这个。我们很高兴:
public void Dispose()
{
try
{
foreach (var extension in OperationContext.Current.Extensions.Where (ex => ex is ARSessionWCFExtention).ToList ())
OperationContext.Current.Extensions.Remove (extension);
Logger.Debug ("Session disposed ClinicID: " + _currentClinic.ClinicID);
}
catch (Exception ex)
{
Logger.Fatal ("Exception message: " + ex.Message + " StackTrace: " + ex.StackTrace);
}
}
但它不起作用OperationContext.Current为null!。在对MSDN进行了数小时毫无意义的搜索后,我发现没有OperationContext,因为OperationContext只有在客户端启动代码时才可用
我现在已经解决了这个问题,将当前的OperationContext和SessionID存储在构造函数中,并在Deconstructor中比较它们,然后使用它们来处理会话
因此,我现在有:
.ctor
{
_current = OperationContext.Current;
_sessionID = OperationContext.Current.SessionId;
OperationContext.Current.Extensions.Add (new ARSessionWCFExtention ());
}
public void Dispose()
{
try
{
OperationContext.Current = _current;
if (OperationContext.Current.SessionId != _sessionID)
throw new Exception("v weird!");
foreach (var extension in OperationContext.Current.Extensions.Where (ex => ex is ARSessionWCFExtention).ToList ())
OperationContext.Current.Extensions.Remove (extension);
Logger.Debug ("Session disposed ClinicID: " + _currentClinic.ClinicID);
}
catch (Exception ex)
{
Logger.Fatal ("Exception message: " + ex.Message + " StackTrace: " + ex.StackTrace);
}
}
有人知道我怎样才能解决这个问题吗
我尝试处理OperationContext.Channel.Close事件,但这不仅仅在客户端触发。事件OperationContext.OperationComplete fire在每次完成调用后发出。这不是我们想要的,我们希望AR会话持续WCF会话的长度。你看到了吗?我读过,但我放弃了它,因为它是关于Ayende UnitOfWork实现的,它使用Castle微内核和Windsor,而我没有。但是现在阅读它,制作一个IContractBehavior/IENDPointBehavior实现可能会很酷,它可以实现。它可能会工作,我会研究一下:好的,我尝试过IServiceBehaviour,但只有在配置服务时才会调用它。所以并不是每一个例子都是这样的:S.IContractBehavior是下一个,这里并没有关于Ayende的工作单元的内容。它确实使用温莎的WCF设施,我建议你也使用它,它会让事情变得更简单。正如我之前所说,我不使用温莎。如果我想使用温莎的WCF设施,我相信我必须重新布线和重写大部分服务实现和DL交互。我们在产品开发方面做得太远了,无法开始进行这种根本性的改变。我发现,如果我将自己的IIntanceProvider实现与IContractBehavior相结合,我应该能够在没有Windsor的情况下实现WCF会话到SessionScope实现:你看到了吗?我读过它,但我放弃了它,因为它是关于Ayende UnitOfWork实现的,它使用Castle微内核和Windsor,而我没有。但是现在阅读它,制作一个IContractBehavior/IENDPointBehavior实现可能会很酷,它可以实现。它可能会工作,我会研究一下:好的,我尝试过IServiceBehaviour,但只有在配置服务时才会调用它。所以并不是每一个例子都是这样的:S.IContractBehavior是下一个,这里并没有关于Ayende的工作单元的内容。它确实使用温莎的WCF设施,我建议你也使用它,它会让事情变得更简单。正如我之前所说,我不使用温莎。如果我想使用温莎的WCF设施,我相信我必须重新布线和重写大部分服务实现和DL交互。我们在产品开发方面做得太远了,无法开始进行这种根本性的改变。我发现,如果我将自己的IIntanceProvider实现与iContractBehavior相结合,我应该能够在没有Windsor的情况下进行WCF会话到SessionScope实现:
.ctor
{
OperationContext.Current.Extensions.Add(new ARSessionWCFExtension());
}
public void Dispose()
{
try
{
foreach (var extension in OperationContext.Current.Extensions.Where (ex => ex is ARSessionWCFExtention).ToList ())
OperationContext.Current.Extensions.Remove (extension);
Logger.Debug ("Session disposed ClinicID: " + _currentClinic.ClinicID);
}
catch (Exception ex)
{
Logger.Fatal ("Exception message: " + ex.Message + " StackTrace: " + ex.StackTrace);
}
}
.ctor
{
_current = OperationContext.Current;
_sessionID = OperationContext.Current.SessionId;
OperationContext.Current.Extensions.Add (new ARSessionWCFExtention ());
}
public void Dispose()
{
try
{
OperationContext.Current = _current;
if (OperationContext.Current.SessionId != _sessionID)
throw new Exception("v weird!");
foreach (var extension in OperationContext.Current.Extensions.Where (ex => ex is ARSessionWCFExtention).ToList ())
OperationContext.Current.Extensions.Remove (extension);
Logger.Debug ("Session disposed ClinicID: " + _currentClinic.ClinicID);
}
catch (Exception ex)
{
Logger.Fatal ("Exception message: " + ex.Message + " StackTrace: " + ex.StackTrace);
}
}