三、服务契约和Host。
1、契约
作为服务契约,需要启用Session,并且设置TransactionFlowOption的等级为Allowed或Mandatory来接收客户端事务流。
作为契约的实现部分,需要设置TransactionScopeRequired为true来启用事务作用域。
①.Customer
[ServiceContract(SessionMode = SessionMode.Required)]
public interface ICustomerContract
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
CustomerInfo Get(object id);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
object Save(CustomerInfo entity);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void Update(CustomerInfo entity);
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class CustomerServer : ICustomerContract
{
public ICustomerManager Manager { get; set; }
[OperationBehavior(TransactionScopeRequired = true)]
public CustomerInfo Get(object id)
{
return Manager.Get(id);
}
[OperationBehavior(TransactionScopeRequired = true)]
public object Save(CustomerInfo entity)
{
return Manager.Save(entity);
}
[OperationBehavior(TransactionScopeRequired = true)]
public void Update(CustomerInfo entity)
{
Manager.Update(entity);
}
public interface ICustomerContract
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
CustomerInfo Get(object id);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
object Save(CustomerInfo entity);
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
void Update(CustomerInfo entity);
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class CustomerServer : ICustomerContract
{
public ICustomerManager Manager { get; set; }
[OperationBehavior(TransactionScopeRequired = true)]
public CustomerInfo Get(object id)
{
return Manager.Get(id);
}
[OperationBehavior(TransactionScopeRequired = true)]
public object Save(CustomerInfo entity)
{
return Manager.Save(entity);
}
[OperationBehavior(TransactionScopeRequired = true)]
public void Update(CustomerInfo entity)
{
Manager.Update(entity);
}
②.Order
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IOrderContract
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
object Save(OrderInfo entity);
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class OrderServer : IOrderContract
{
public IOrderManager Manager { get; set; }
[OperationBehavior(TransactionScopeRequired = true)]
public object Save(OrderInfo entity)
{
return Manager.Save(entity);
}
}
public interface IOrderContract
{
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
object Save(OrderInfo entity);
}
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class OrderServer : IOrderContract
{
public IOrderManager Manager { get; set; }
[OperationBehavior(TransactionScopeRequired = true)]
public object Save(OrderInfo entity)
{
return Manager.Save(entity);
}
}
2、配置
然而,Spring.NET针对NHibernate的Session管理使用的是OSIV模式(Open Session In View),即使用httpModule去拦截HTTP请求,在每次请求开始时打开Session作用域(SessionScope),最后在请求结束后关闭SessionScope。这样一来,在客户端每请求一次时都会打开SessionScope,在请求结束会关闭SessionScope,然后当请求结束后再去处理分布式就会提示“无法使用已释放对象”的错误。所以说,OSIV是无法正常管理分布式事务的。出于上述原因,我们决定在Global.asax的配置,在Session(这里的Session是ASP.NET中的Session)启动时候打开SessionScope,在Session结束时关闭SessionScope。这样分布式事务就会与SessionScope同步了。
最后,在配置appSettings节点增加
另外配置WCF的binding时需要选择一种支持Session的binding(如wsHttpBinding)并且将binding中的transactionFlow属性设置为true。
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
log4net.Config.XmlConfigurator.Configure();
}
protected void Session_Start(object sender, EventArgs e)
{
SessionScope sessionScope = new SessionScope("appSettings", typeof(SessionScope), false);
sessionScope.Open();
HttpContext.Current.Session["SessionScope"] = sessionScope;
}
protected void Session_End(object sender, EventArgs e)
{
SessionScope sessionScope = HttpContext.Current.Session["SessionScope"] as SessionScope;
if (sessionScope != null)
{
sessionScope.Close();
}
}
}
{
protected void Application_Start(object sender, EventArgs e)
{
log4net.Config.XmlConfigurator.Configure();
}
protected void Session_Start(object sender, EventArgs e)
{
SessionScope sessionScope = new SessionScope("appSettings", typeof(SessionScope), false);
sessionScope.Open();
HttpContext.Current.Session["SessionScope"] = sessionScope;
}
protected void Session_End(object sender, EventArgs e)
{
SessionScope sessionScope = HttpContext.Current.Session["SessionScope"] as SessionScope;
if (sessionScope != null)
{
sessionScope.Close();
}
}
}
①.Customer
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configuration>
<%@ ServiceHost Language="C#" Debug="true" Service="Customer.Host" Factory="Spring.ServiceModel.Activation.ServiceHostFactory"%>