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

简介:
[索引页]
[源码下载] 


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


作者: webabcd


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


示例
1、服务
Hello.cs
InBlock.gif using System; 
InBlock.gif using System.Collections.Generic; 
InBlock.gif using System.Linq; 
InBlock.gif using System.Text; 
InBlock.gif 
InBlock.gif using System.ServiceModel; 
InBlock.gif 
InBlock.gif namespace WCF.ServiceLib.Transaction 
InBlock.gif
InBlock.gif         /// <summary> 
InBlock.gif         /// IHello接口 
InBlock.gif         /// </summary> 
InBlock.gif        [ServiceContract] 
InBlock.gif         public  interface IHello 
InBlock.gif        { 
InBlock.gif                 /// <summary> 
InBlock.gif                 /// 打招呼方法 
InBlock.gif                 /// </summary> 
InBlock.gif                 /// <param name="name">人名</param> 
InBlock.gif                 /// <remarks> 
InBlock.gif                /// TransactionFlow - 指定服务操作是否愿意接受来自客户端的传入事务 
InBlock.gif                /// NotAllowed - 禁止事务。默认值 
InBlock.gif                /// Allowed - 允许事务 
InBlock.gif                /// Mandatory - 强制事务 
InBlock.gif                /// </remarks> 

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

InBlock.gif                 /// <returns></returns> 
InBlock.gif                [OperationBehavior(TransactionScopeRequired =  true, TransactionAutoComplete =  true)] 
InBlock.gif                 public  void WriteHello( string name) 
InBlock.gif                { 
InBlock.gif                        DBDataContext ctx =  new DBDataContext(); 
InBlock.gif 
InBlock.gif                        ctx.Items.InsertOnSubmit( 
InBlock.gif                                 new Item 
InBlock.gif                                { 
InBlock.gif                                        Title =  string.Format( "Hello: {0}, TransactionId: {1}", name, System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier), 
InBlock.gif                                        CreatedTime = DateTime.Now 
InBlock.gif                                }); 
InBlock.gif 
InBlock.gif                        ctx.SubmitChanges(); 
InBlock.gif                } 
InBlock.gif        } 
InBlock.gif}
 
Hi.cs
InBlock.gif using System; 
InBlock.gif using System.Collections.Generic; 
InBlock.gif using System.Linq; 
InBlock.gif using System.Text; 
InBlock.gif 
InBlock.gif using System.ServiceModel; 
InBlock.gif 
InBlock.gif namespace WCF.ServiceLib.Transaction 
InBlock.gif
InBlock.gif         /// <summary> 
InBlock.gif         /// IHi接口 
InBlock.gif         /// </summary> 
InBlock.gif        [ServiceContract] 
InBlock.gif         public  interface IHi 
InBlock.gif        { 
InBlock.gif                 /// <summary> 
InBlock.gif                 /// 打招呼方法 
InBlock.gif                 /// </summary> 
InBlock.gif                 /// <param name="name">人名</param> 
InBlock.gif                 /// <returns></returns> 
InBlock.gif                [OperationContract] 
InBlock.gif                [TransactionFlow(TransactionFlowOption.Mandatory)] 
InBlock.gif                 void WriteHi( string name); 
InBlock.gif        } 
InBlock.gif 
InBlock.gif         /// <summary> 
InBlock.gif         /// Hi类 
InBlock.gif         /// </summary> 
InBlock.gif         public  class Hi : IHi 
InBlock.gif        { 
InBlock.gif                 /// <summary> 
InBlock.gif                 /// 打招呼方法 
InBlock.gif                 /// </summary> 
InBlock.gif                 /// <param name="name">人名</param> 
InBlock.gif                 /// <returns></returns> 
InBlock.gif                [OperationBehavior(TransactionScopeRequired =  true, TransactionAutoComplete =  true)] 
InBlock.gif                 public  void WriteHi( string name) 
InBlock.gif                { 
InBlock.gif                         if (DateTime.Now.Second % 2 == 0) 
InBlock.gif                                 throw  new System.Exception( "为测试事务而抛出的异常"); 
InBlock.gif 
InBlock.gif                        DBDataContext ctx =  new DBDataContext(); 
InBlock.gif 
InBlock.gif                        ctx.Items.InsertOnSubmit( 
InBlock.gif                                 new Item 
InBlock.gif                                { 
InBlock.gif                                        Title =  string.Format( "Hi: {0}, TransactionId: {1}", name, System.Transactions.Transaction.Current.TransactionInformation.LocalIdentifier), 
InBlock.gif                                        CreatedTime = DateTime.Now 
InBlock.gif                                }); 
InBlock.gif 
InBlock.gif                        ctx.SubmitChanges(); 
InBlock.gif                } 
InBlock.gif        } 
InBlock.gif}
 
Result.cs
InBlock.gif using System; 
InBlock.gif using System.Collections.Generic; 
InBlock.gif using System.Linq; 
InBlock.gif using System.Text; 
InBlock.gif 
InBlock.gif using System.ServiceModel; 
InBlock.gif 
InBlock.gif namespace WCF.ServiceLib.Transaction 
InBlock.gif
InBlock.gif         /// <summary> 
InBlock.gif         /// 结果接口 
InBlock.gif         /// </summary> 
InBlock.gif        [ServiceContract] 
InBlock.gif         public  interface IResult 
InBlock.gif        { 
InBlock.gif                [OperationContract] 
InBlock.gif                List<Item> GetResult(); 
InBlock.gif        } 
InBlock.gif 
InBlock.gif         /// <summary> 
InBlock.gif         /// 结果类 
InBlock.gif         /// </summary> 
InBlock.gif         public  class Result : IResult 
InBlock.gif        { 
InBlock.gif                 /// <summary> 
InBlock.gif                 /// 返回数据库结果 
InBlock.gif                 /// </summary> 
InBlock.gif                 /// <returns></returns> 
InBlock.gif                 public List<Item> GetResult() 
InBlock.gif                { 
InBlock.gif                        DBDataContext ctx =  new DBDataContext(); 
InBlock.gif 
InBlock.gif                        var result = from l  in ctx.Items 
InBlock.gif                                                 orderby l.CreatedTime descending 
InBlock.gif                                                 select l; 
InBlock.gif 
InBlock.gif                         return result.ToList(); 
InBlock.gif                } 
InBlock.gif        } 
InBlock.gif}
 
 

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
InBlock.gif using System; 
InBlock.gif using System.Collections; 
InBlock.gif using System.Configuration; 
InBlock.gif using System.Data; 
InBlock.gif using System.Linq; 
InBlock.gif using System.Web; 
InBlock.gif using System.Web.Security; 
InBlock.gif using System.Web.UI; 
InBlock.gif using System.Web.UI.HtmlControls; 
InBlock.gif using System.Web.UI.WebControls; 
InBlock.gif using System.Web.UI.WebControls.WebParts; 
InBlock.gif using System.Xml.Linq; 
InBlock.gif 
InBlock.gif using System.Threading; 
InBlock.gif 
InBlock.gif public partial  class Transaction_Sample : System.Web.UI.Page 
InBlock.gif
InBlock.gif         protected  void Page_Load( object sender, EventArgs e) 
InBlock.gif        { 
InBlock.gif 
InBlock.gif        } 
InBlock.gif 
InBlock.gif         protected  void btnSubmit_Click( object sender, EventArgs e) 
InBlock.gif        { 
InBlock.gif                var proxyHello =  new TransactionSvc.Hello.HelloClient(); 
InBlock.gif                var proxyHi =  new TransactionSvc.Hi.HiClient(); 
InBlock.gif                var proxyResult =  new TransactionSvc.Result.ResultClient(); 
InBlock.gif 
InBlock.gif                System.Transactions.TransactionOptions to =  new System.Transactions.TransactionOptions(); 
InBlock.gif                 // 设置事务的超时时间 
InBlock.gif                to.Timeout =  new TimeSpan(0, 0, 30); 
InBlock.gif                 // 设置事务的隔离级别 
InBlock.gif                to.IsolationLevel = System.Transactions.IsolationLevel.Serializable; 
InBlock.gif 
InBlock.gif                 using (var ts =  new System.Transactions.TransactionScope()) 
InBlock.gif                { 
InBlock.gif                         try 
InBlock.gif                        { 
InBlock.gif                                proxyHello.WriteHello( "webabcd"); 
InBlock.gif                                proxyHello.Close(); 
InBlock.gif 
InBlock.gif                                proxyHi.WriteHi( "webabcd"); 
InBlock.gif                                proxyHi.Close(); 
InBlock.gif 
InBlock.gif                                ts.Complete(); 
InBlock.gif 
InBlock.gif                                lblErr.Text =  "OK"
InBlock.gif                        } 
InBlock.gif                         catch (Exception ex) 
InBlock.gif                        { 
InBlock.gif                                lblErr.Text = ex.ToString(); 
InBlock.gif                        } 
InBlock.gif                } 
InBlock.gif 
InBlock.gif                GridView1.DataSource = proxyResult.GetResult(); 
InBlock.gif                GridView1.DataBind(); 
InBlock.gif                proxyHello.Close(); 
InBlock.gif        } 
InBlock.gif}
 
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
[源码下载]
 

     本文转自webabcd 51CTO博客,原文链接:http://blog.51cto.com/webabcd/344160 ,如需转载请自行联系原作者
相关文章