关于wcf:仅在客户端启动了事务


Transaction started only on client side

我需要实现以下场景:如果客户机启动事务,它将流向服务器,但如果客户机不启动事务,则必须在不执行事务的情况下执行服务方法。有可能吗?在我的例子中,没有transactionscopererequired=true,事务不会流动。

服务器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 <system.serviceModel>
  <bindings>
   <netTcpBinding>
    <binding name="tcpTransactional" transactionFlow="true" />
   </netTcpBinding>
  </bindings>
  <services>
   <service name="WcfServiceLibrary1.TcpTransactionalService">
    <endpoint address="" binding="netTcpBinding" bindingConfiguration="tcpTransactional"
     contract="WcfServiceLibrary1.ITcpTransactionalService">
     <identity>
      <dns value="localhost" />
     </identity>
    </endpoint>
    <endpoint address="mex" binding="mexTcpBinding" bindingConfiguration=""
     contract="IMetadataExchange" />
    <host>
     <baseAddresses>
     
     
     </baseAddresses>
    </host>
   </service>
  </services>
  <behaviors>
   <serviceBehaviors>
    <behavior>
     <!-- To avoid disclosing metadata information,
     set the value below to false and remove the metadata endpoint above before deployment -->
     <serviceMetadata httpGetEnabled="True"/>
     <!-- To receive exception details in faults for debugging purposes,
     set the value below to true. Set to false before deployment
     to avoid disclosing exception information -->
     <serviceDebug includeExceptionDetailInFaults="False" />
    </behavior>
   </serviceBehaviors>
  </behaviors>
 </system.serviceModel>

    [ServiceContract]
    public interface ITcpTransactionalService
    {
        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Allowed)]
        void DoWork();
    }

    //[OperationBehavior(TransactionScopeRequired = true)]
    public void DoWork()
    {
      Debug.Assert(Transaction.Current != null);
      Debug.Assert(Transaction.Current.TransactionInformation.DistributedIdentifier != Guid.Empty);
    }

客户:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name="NetTcpBinding_ITcpTransactionalService" closeTimeout="00:01:00"
          openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
          transactionFlow="true" transferMode="Buffered" transactionProtocol="OleTransactions"
          hostNameComparisonMode="StrongWildcard" listenBacklog="10"
          maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
          maxReceivedMessageSize="65536">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <reliableSession ordered="true" inactivityTimeout="00:10:00"
            enabled="false" />
          <security mode="Transport">
            <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
            <message clientCredentialType="Windows" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint address="net.tcp://localhost:8730/Design_Time_Addresses/WcfServiceLibrary1/TcpTransactionalService/"
        binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ITcpTransactionalService"
        contract="TcpTransactionalService.ITcpTransactionalService"
        name="NetTcpBinding_ITcpTransactionalService">
        <identity>
          <dns value="localhost" />
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>

    private static void TestTcp()
    {
      using (var scope = new TransactionScope())
      {
        var client = new TcpTransactionalService.TcpTransactionalServiceClient();
        client.DoWork();

        Debug.Assert(Transaction.Current != null);
        Debug.Assert(Transaction.Current.TransactionInformation.DistributedIdentifier != Guid.Empty);

        scope.Complete();
      }
    }

使用TransactionScopeRequire=true

如果客户机不发送事务,则不会以分布式事务结束。如果有,那么你有

现在,这仍然会在本地事务中调用您的操作。如果要取消显示,请检查分布式标识符。如果其guid.empty,则在创建如下的另一个TransactionScope中运行其余代码:

1
2
3
4
5
6
7
8
9
10
11
12
 if (Transaction.Current.TransactionInformation.DistributedIdentifier == Guid.Empty)
 {
    using (var scope = new TransactionScope(TransactionScopeOption.Suppress))
    {
       DoWork();
       scope.Complete();
    }
 }
 else
 {
        DoWork();
 }