WCF(三)分布式事务

最近在学WCF,所以有两个设想疑问(菜鸟多疑问):

  • 如果有WCF服务A,WCF服务B,客户端调用WCF服务A插入一条数据,然后再调用服务B也插入一条数据,然而服务B出错了进行了回滚,服务A能不能也进行回滚操作?
  • 或是客户端调用服务A和服务B,成功了插入了两条数据之后,客户端这边出错了,如何让服务A和服务B插入的数据也回滚操作?

经过学习探索,了解到WCF支持分布式事务,事务可以在多个服务中传播,也可以在服务端与客户端之间传播。

注:WCF内并非所有绑定都支持事务的,常用的BasicHttpBinding就不支持事务的传播。只有以下几个绑定才能支持事务流的运转:NetTcpBinding、WSHttpBinding、WSDualHttpBinding、WSFederationHttpBinding、NetNamedPipeBinding。

代码尝试

先建一个WCF服务(WSHttpBinding),有两个Add方法,在客户端两次分开调用

 [ServiceContract]
    public interface IService1
    {

        [OperationContract]
        string AddData_1(string a);

        [OperationContract]
        string AddData_2(string a);

    }

 

 public class Service1 : IService1
    {
       
        [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
        [TransactionFlow(TransactionFlowOption.Allowed)]
        public string AddData_1(string b)
        {
            using (testEntities ts = new testEntities())
            {
                Student a = new Student()
                {
                    Age = 9999999,
                    Class = b,
                    Sex = "",
                    Score = 100
                };
                ts.Student.Add(a);
                ts.SaveChanges();     
            }
            return "22222";
        }
       
        [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
        [TransactionFlow(TransactionFlowOption.Allowed)]
        public string AddData_2(string b)
        {
            using (testEntities ts = new testEntities())
            {
                Student a = new Student()
                {
                    Age = 9999999,
                    Class = b,
                    Sex = "",
                    Score = 100
                };
                ts.Student.Add(a);
                ts.SaveChanges();
                throw new Exception("出错拉!");  //抛出错误
            }

            return "22222";
        }
    }

其中标红解释:

TransactionScopeRequired:值为true时,表示此WCF服务的方法中启动事务,为false,反之不启动。

TransactionAutoComplete:值为true时为隐式事务,方法在运行过程中没有抛出Exception,事务会自动提交。如果期间出现任何异常,事务就会自动回滚;false时,显式事务,必须OperationContext.Current.SetTransactionComplete () 显式提交事务。

TransactionFlowOption:设置为Allowed,开启事务传播,客户端的事务传播到服务端。

        有三个值:

      NotAllowed,禁止客户端传播事务流到服务端,即使客户端启动了事务,该事务也会被忽略;

        Allowed,允许客户端的事务传播到服务端,但服务器端不一定会引用到此事务(如果服务端方法没开启事务);

      Mandatory,服务端与客户端必须同时启动事务流,否则就会抛出InvalidOperationException异常。

web.config配置(重要)

服务端web.config

<configuration>
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <!--启动事务流-->
        <binding name="defaultWSHttpBinding" transactionFlow="true" />   <!--这里一定要设置绑定的transactionFlow为true,否则无法使用事务-->  
      </wsHttpBinding>
    </bindings>
    
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service name="WcfDemo_shiwu.Service1">
        <endpoint address="" binding="wsHttpBinding"
           contract="WcfDemo_shiwu.IService1" bindingConfiguration="defaultWSHttpBinding"/>   <!--这里一定要设置bindingConfiguration--> 
      </service>
    </services>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <!--
        若要在调试过程中浏览 Web 应用程序根目录,请将下面的值设置为 True。
        在部署之前将该值设置为 False 可避免泄露 Web 应用程序文件夹信息。
      -->
    <directoryBrowse enabled="true" />
  </system.webServer>
</configuration>

 客户端

<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
    </startup>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="WSHttpBinding_IService1" transactionFlow="true" />
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:5854/Service1.svc" binding="wsHttpBinding"
                bindingConfiguration="WSHttpBinding_IService1" contract="TestService.IService1"
                name="WSHttpBinding_IService1">
                <identity>
                    <userPrincipalName value="DESKTOP-350R9O7\qiuguochao" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

客户端代码

情况一:WCF服务中的方法2报错回滚,那么之前第一次调用插入的是否成功回滚?

 static void Main(string[] args)
        {
            //客户端开启分布式事务,要引用System.Transactions.dll
            using (TransactionScope ts = new TransactionScope())
            {
                //调用服务
                using (TestService.Service1Client service = new TestService.Service1Client())
                {
                    service.AddData_1("1");

                }
Console.WriteLine(
"第一次调用:成功插入一条数据");

          //重新去调用WCF服务
using (TestService.Service1Client service2 = new TestService.Service1Client()) { //WCF中的AddData_2会报错 service2.AddData_2("2"); } ts.Complete(); } }

结果:

WCF服务插入第二条数据,已经报错,因为该方法中已经设置  [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)],开启了事务,所以第二数据肯定是会被回滚的

且看第一条数据是否也会被回滚?,结果是两条数据都被回滚了

 

情况2:两次调用WCF服务成功插入数据后,客户端报错回滚,在WCF服务中插入的数据是否也回滚?

将抛出错误注释掉,重新运行WCF服务

改写客户端代码,并设下断点:

 

 执行到断点,查看数据情况

已经成功插入,继续执行,由于没有进行提交,所以该事务将会自动回滚,且看在WCF服务中插入的数据是否会被回滚

客户端进行了回滚操作,很显然,客户端的事务传播的WCF中的方法事务,也将相应的操作回滚。

 

posted @ 2018-05-10 09:37 三瓜两枣 阅读(...) 评论(...) 编辑 收藏