化零为整WCF(14) - 事务(Transaction)

本文介绍如何在WCF中使用事务,包括对契约方法使用TransactionFlowAttribute声明、对服务方法使用OperationBehaviorAttribute声明以及配置binding节点的transactionFlow属性等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[索引页]
[源码下载]


化零为整WCF(14) - 事务(Transaction)


作者: webabcd


介绍
WCF(Windows Communication Foundation) - 事务(Transaction):
    ·对契约方法使用TransactionFlowAttribute声明(设置TransactionFlowOption参数),以指定服务操作的事务流策略
    ·对
服务方法是用OperationBehaviorAttribute声明(设置TransactionScopeRequired参数),以指定方法是否在事务范围(TransactionScope)内执行
    ·
配置host和client的binding节点的transactionFlow属性,以指定绑定是否支持流事务


示例
1、服务
Hello.cs
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;

using  System.ServiceModel;

namespace  WCF.ServiceLib.Transaction
{
    
/// <summary>
    
/// IHello接口
    
/// </summary>

    [ServiceContract]
    
public interface IHello
    
{
        
/// <summary>
        
/// 打招呼方法
        
/// </summary>
        
/// <param name="name">人名</param>
        
/// <remarks>
        
/// TransactionFlow - 指定服务操作是否愿意接受来自客户端的传入事务
        
/// NotAllowed - 禁止事务。默认值
        
/// Allowed - 允许事务
        
/// Mandatory - 强制事务
        
/// </remarks>
        
/// <returns></returns>

        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Mandatory)]
        
void WriteHello(string name);
    }


    
/// <summary>
    
/// Hello类
    
/// </summary>

    public class Hello : IHello
    
{
        
/// <summary>
        
/// 打招呼方法
        
/// </summary>
        
/// <param name="name">人名</param>
        
/// <remarks>
        
/// OperationBehavior - 指定服务方法的本地执行行为
        
/// 1、TransactionScopeRequired - 如果方法需要事务范围才能执行,则为 true;否则为 false。默认值为 false
        
/// 将 TransactionScopeRequired 设置为 true,可以要求操作在事务范围内执行。如果流事务可用,则操作会在该事务内执行。如果流事务不可用,则会创建一个新事务并使用它来执行操作
        
/// 2、TransactionAutoComplete - 默认值为 true
        
/// true - 当方法完成执行时,将把该事务标志为完成(自动提交事务)
        
/// false - 需要调用OperationContext.Current.SetTransactionComplete()方法来手工配置该事务的正确完成;否则,该事务将被标志为失败(手动提交事务)
        
/// </remarks>
        
/// <returns></returns>

        [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
        
public void WriteHello(string name)
        
{
            DBDataContext ctx 
= new DBDataContext();

            ctx.Items.InsertOnSubmit(
                
new Item
                
{
                    Title 
= string.Format("Hello: {0}, TransactionId: {1}", name, System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier),
                    CreatedTime 
= DateTime.Now
                }
);

            ctx.SubmitChanges();
        }

    }

}


Hi.cs
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;

using  System.ServiceModel;

namespace  WCF.ServiceLib.Transaction
{
    
/// <summary>
    
/// IHi接口
    
/// </summary>

    [ServiceContract]
    
public interface IHi
    
{
        
/// <summary>
        
/// 打招呼方法
        
/// </summary>
        
/// <param name="name">人名</param>
        
/// <returns></returns>

        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Mandatory)]
        
void WriteHi(string name);
    }


    
/// <summary>
    
/// Hi类
    
/// </summary>

    public class Hi : IHi
    
{
        
/// <summary>
        
/// 打招呼方法
        
/// </summary>
        
/// <param name="name">人名</param>
        
/// <returns></returns>

        [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
        
public void WriteHi(string name)
        
{
            
if (DateTime.Now.Second % 2 == 0)
                
throw new System.Exception("为测试事务而抛出的异常");

            DBDataContext ctx 
= new DBDataContext();

            ctx.Items.InsertOnSubmit(
                
new Item
                
{
                    Title 
= string.Format("Hi: {0}, TransactionId: {1}", name, System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier),
                    CreatedTime 
= DateTime.Now
                }
);

            ctx.SubmitChanges();
        }

    }

}


Result.cs
using  System;
using  System.Collections.Generic;
using  System.Linq;
using  System.Text;

using  System.ServiceModel;

namespace  WCF.ServiceLib.Transaction
{
    
/// <summary>
    
/// 结果接口
    
/// </summary>

    [ServiceContract]
    
public interface IResult
    
{
        [OperationContract]
        List
<Item> GetResult();
    }


    
/// <summary>
    
/// 结果类
    
/// </summary>

    public class Result : IResult
    
{
        
/// <summary>
        
/// 返回数据库结果
        
/// </summary>
        
/// <returns></returns>

        public List<Item> GetResult()
        
{
            DBDataContext ctx 
= new DBDataContext();

            var result 
= from l in ctx.Items
                         orderby l.CreatedTime descending
                         select l;

            
return result.ToList();
        }

    }

}



2、宿主
Hello.svc
<% @ ServiceHost Language="C#" Debug="true" Service="WCF.ServiceLib.Transaction.Hello"  %>

Hi.svc
<% @ ServiceHost Language="C#" Debug="true" Service="WCF.ServiceLib.Transaction.Hi"  %>

Result.svc
<% @ ServiceHost Language="C#" Debug="true" Service="WCF.ServiceLib.Transaction.Result"  %>

Web.config
<? xml version="1.0" ?>
< configuration >
    
< system.serviceModel >
        
< behaviors >
            
< serviceBehaviors >
                
< behavior  name ="TransactionBehavior" >
                    
<!-- httpGetEnabled - 指示是否发布服务元数据以便使用 HTTP/GET 请求进行检索,如果发布 WSDL,则为 true,否则为 false,默认值为 false -->
                    
< serviceMetadata  httpGetEnabled ="true"   />
                    
< serviceDebug  includeExceptionDetailInFaults ="true" />
                
</ behavior >
            
</ serviceBehaviors >
        
</ behaviors >
        
< services >
            
<!-- name - 提供服务的类名 -->
            
<!-- behaviorConfiguration - 指定相关的行为配置 -->
            
< service  name ="WCF.ServiceLib.Transaction.Hello"  behaviorConfiguration ="TransactionBehavior" >
                
<!-- address - 服务地址 -->
                
<!-- binding - 通信方式 -->
                
<!-- contract - 服务契约 -->
                
<!-- bindingConfiguration - 指定相关的绑定配置 -->
                
< endpoint  address =""  binding ="wsHttpBinding"  contract ="WCF.ServiceLib.Transaction.IHello"  bindingConfiguration ="TransactionConfiguration"   />
            
</ service >
            
< service  name ="WCF.ServiceLib.Transaction.Hi"  behaviorConfiguration ="TransactionBehavior" >
                
< endpoint  address =""  binding ="wsHttpBinding"  contract ="WCF.ServiceLib.Transaction.IHi"  bindingConfiguration ="TransactionConfiguration"   />
            
</ service >
            
< service  name ="WCF.ServiceLib.Transaction.Result"  behaviorConfiguration ="TransactionBehavior" >
                
< endpoint  address =""  binding ="basicHttpBinding"  contract ="WCF.ServiceLib.Transaction.IResult"   />
            
</ service >
        
</ services >
        
< bindings >
            
< wsHttpBinding >
                
<!-- transactionFlow - 指定该绑定是否应支持流事务 -->
                
< binding  name ="TransactionConfiguration"  transactionFlow ="true"   />
            
</ wsHttpBinding >
        
</ bindings >
    
</ system.serviceModel >
</ configuration >


3、客户端
Sample.aspx
<% @ Page Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Sample.aspx.cs"
    Inherits
="Transaction_Sample" Title="事务(Transaction)" 
%>

< asp:Content  ID ="Content1"  ContentPlaceHolderID ="head"  runat ="Server" >
</ asp:Content >
< asp:Content  ID ="Content2"  ContentPlaceHolderID ="ContentPlaceHolder1"  runat ="Server" >
    
< p >
        
< asp:Label  ID ="lblErr"  runat ="server"  ForeColor ="Red"   />
    
</ p >
    
< p >
        
< asp:Button  ID ="btnSubmit"  runat ="server"  Text ="事务测试"  OnClick ="btnSubmit_Click"   />
        
< br  />
        
< br  />
        
< asp:GridView  ID ="GridView1"  runat ="server" >
        
</ asp:GridView >
    
</ p >
    
< p >
        2PC(Two Phase Commitment Protocol)两阶段提交协议(WCF的事务的实现基于此协议)
        
< br  />
        实现分布式事务的关键就是两阶段提交协议。在此协议中,一个或多个资源管理器的活动均由一个称为事务协调器的单独软件组件来控制。此协议中的五个步骤如下:
        
< br  />
        1、应用程序调用事务协调器中的提交方法。
        
< br  />
        2、事务协调器将联络事务中涉及的每个资源管理器,并通知它们准备提交事务(这是第一阶段的开始)。
        
< br  />
        3、为 了以肯定的方式响应准备阶段,资源管理器必须将自己置于以下状态:确保能在被要求提交事务时提交事务,或在被要求回滚事务时回滚事务。大多数资源管理器会将包含其计划更改的日记文件(或等效文件)写入持久存储区中。如果资源管理器无法准备事务,它会以一个否定响应来回应事务协调器。
        
< br  />
        4、事务协调器收集来自资源管理器的所有响应。
        
< br  />
        5、在 第二阶段,事务协调器将事务的结果通知给每个资源管理器。如果任一资源管理器做出否定响应,则事务协调器会将一个回滚命令发送给事务中涉及的所有资源管理 器。如果资源管理器都做出肯定响应,则事务协调器会指示所有的资源管理器提交事务。一旦通知资源管理器提交,此后的事务就不能失败了。通过以肯定的方式响应第一阶段,每个资源管理器均已确保,如果以后通知它提交事务,则事务不会失败。
    
</ p >
</ asp:Content >

Sample.aspx.cs
using  System;
using  System.Collections;
using  System.Configuration;
using  System.Data;
using  System.Linq;
using  System.Web;
using  System.Web.Security;
using  System.Web.UI;
using  System.Web.UI.HtmlControls;
using  System.Web.UI.WebControls;
using  System.Web.UI.WebControls.WebParts;
using  System.Xml.Linq;

using  System.Threading;

public   partial   class  Transaction_Sample : System.Web.UI.Page
{
    
protected void Page_Load(object sender, EventArgs e)
    
{

    }


    
protected void btnSubmit_Click(object sender, EventArgs e)
    
{
        var proxyHello 
= new TransactionSvc.Hello.HelloClient();
        var proxyHi 
= new TransactionSvc.Hi.HiClient();
        var proxyResult 
= new TransactionSvc.Result.ResultClient();

        System.Transactions.TransactionOptions to 
= new System.Transactions.TransactionOptions();
        
// 设置事务的超时时间
        to.Timeout = new TimeSpan(0030);
        
// 设置事务的隔离级别
        to.IsolationLevel = System.Transactions.IsolationLevel.Serializable;

        
using (var ts = new System.Transactions.TransactionScope())
        
{
            
try
            
{
                proxyHello.WriteHello(
"webabcd");
                proxyHello.Close();

                proxyHi.WriteHi(
"webabcd");
                proxyHi.Close();

                ts.Complete();

                lblErr.Text 
= "OK";
            }

            
catch (Exception ex)
            
{
                lblErr.Text 
= ex.ToString();
            }

        }


        GridView1.DataSource 
= proxyResult.GetResult();
        GridView1.DataBind();
        proxyHello.Close();
    }

}


Web.config
<? xml version="1.0" ?>
< configuration >
    
< system.serviceModel >
        
< client >
            
<!-- address - 服务地址 -->
            
<!-- binding - 通信方式 -->
            
<!-- contract - 服务契约 -->
            
< endpoint  address ="http://localhost:3502/ServiceHost/Transaction/Hello.svc"  binding ="wsHttpBinding"  contract ="TransactionSvc.Hello.IHello"  bindingConfiguration ="TransactionBindingConfiguration"   />
            
< endpoint  address ="http://localhost:3502/ServiceHost/Transaction/Hi.svc"  binding ="wsHttpBinding"  contract ="TransactionSvc.Hi.IHi"  bindingConfiguration ="TransactionBindingConfiguration"   />
            
< endpoint  address ="http://localhost:3502/ServiceHost/Transaction/Result.svc"  binding ="basicHttpBinding"  contract ="TransactionSvc.Result.IResult"   />
        
</ client >
        
< bindings >
            
< wsHttpBinding >
                
<!-- transactionFlow - 指定该绑定是否应支持流事务 -->
                
< binding  name ="TransactionBindingConfiguration"  transactionFlow ="true"   />
            
</ wsHttpBinding >
        
</ bindings >
    
</ system.serviceModel >
</ configuration >


运行结果:
单击"btnSubmit"按钮后,可以发现,两个数据库插入操作,要么都执行,要么都不执行


OK
[源码下载]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值