这可能是一个小众问题,但也许有人可以帮助我。我正在将我的 Web 服务从 ASMX 移植到 WCF,但是我完全建立在 Castle ActiveRecord 上。为了确保我的配置中没有某种奇怪的问题,我使用来自 NuGet 的所有最新 Castle 和 NHibernate 库从头开始构建了一个独立的重现。
我做的第一件事是在Application_Start
. 通常我会使用一个web.config
实例,但这可能无关紧要:
protected void Application_Start(object sender, EventArgs e)
{
//NHibernate.Driver.OracleClientDriver
IDictionary<string, string> properties = new Dictionary<string, string>();
properties.Add("connection.driver_class", "NHibernate.Driver.OracleClientDriver");
properties.Add("dialect", "NHibernate.Dialect.Oracle10gDialect");
properties.Add("connection.provider", "NHibernate.Connection.DriverConnectionProvider");
properties.Add("connection.connection_string", "user Id=xxx;password=xxx;server=localhost;persist security info=True");
properties.Add("proxyfactory.factory_class", "NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle");
InPlaceConfigurationSource source = new InPlaceConfigurationSource();
source.IsRunningInWebApp = true;
source.ThreadScopeInfoImplementation = typeof(Castle.ActiveRecord.Framework.Scopes.HybridWebThreadScopeInfo);
source.Add(typeof(ActiveRecordBase), properties);
ActiveRecordStarter.Initialize(source, typeof(Task), typeof(Project));
}
请注意,我也在使用该HybridWebThreadScopeInfo
实现,因为HttpContext.Current
在 WCF 中将为空。
接下来,我实现我的 Web 服务:
public class Service1 : IService1
{
public string GetData(int value)
{
Project p;
p = Project.Find(123M);
var count = p.Tasks.Count(); //Force count query
return p.GoldDate.ToString();
}
}
当我打电话时Project.Find()
,它工作正常。接下来,我调用p.Tasks.Count()
which 将强制执行新查询,因为该Tasks
属性是惰性的。当我这样做时,我得到了异常:
Initializing[NHTest.Project#123] - 无法延迟初始化角色集合:NHTest.Project.Tasks,没有会话或会话已关闭
发生这种情况的原因是因为没有会话范围。我猜如果内部ActiveRecordBase
方法不存在或其他东西,它会创建一个会话。现在,我可以用这个手动创建一个:
public string GetData(int value)
{
Project p;
using (new SessionScope())
{
p = Project.Find(123M);
var count = p.Tasks.Count(); //Force count query
return p.GoldDate.ToString();
}
}
这会很好用。但是,我不想在我的所有代码中都这样做,因为这在 ASP.NET Web 服务中非常有效。
那么为什么它可以在 ASP.NET 中工作呢?
之所以有效,是因为 ActiveRecord 带有一个名为Castle.ActiveRecord.Framework.SessionScopeWebModule
. 这个模块在每个 HTTP 请求之前运行,并在 ActiveRecord 中创建一个默认会话。但是,在 WCF HTTP 请求之前不会调用此模块。
ASP.NET 兼容模式呢?
您可以使用以下方法启用 ASP.NET 兼容模式:
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" ... />
这也将解决问题,并提供对 WCF 中 HTTP 请求管道的其他访问。这将是一种解决方案。但是,尽管它可以在 Visual Studio 测试网络服务器上运行,但我从来没有能够让兼容模式在 IIS7 上运行。另外,我觉得最好的设计是完全在 WCF 基础架构内工作。
我的问题:
Castle ActiveRecord 是否提供在 WCF 请求中创建会话范围的能力?如果是这样,这是如何配置的?