Sdílet prostřednictvím


Postupy: Vytvoření transakční služby

Tato ukázka ukazuje různé aspekty vytvoření transakční služby a použití transakce iniciované klientem ke koordinaci operací služby.

Vytvoření transakční služby

  1. Vytvořte kontrakt služby a anotujte operace s požadovaným nastavením z výčtu TransactionFlowOption , abyste určili požadavky na příchozí transakce. Všimněte si, že můžete také umístit třídu TransactionFlowAttribute služby, která se implementuje. To umožňuje, aby jedna implementace rozhraní používala tato nastavení transakcí místo každé implementace.

    [ServiceContract]  
    public interface ICalculator  
    {  
        [OperationContract]  
        // Use this to require an incoming transaction  
        [TransactionFlow(TransactionFlowOption.Mandatory)]  
        double Add(double n1, double n2);  
        [OperationContract]  
        // Use this to permit an incoming transaction  
        [TransactionFlow(TransactionFlowOption.Allowed)]  
        double Subtract(double n1, double n2);  
    }  
    
  2. Vytvořte implementační třídu a použijte ServiceBehaviorAttribute ji k volitelnému určení a TransactionIsolationLevel .TransactionTimeout Měli byste si uvědomit, že v mnoha případech je výchozí TransactionTimeout hodnota 60 sekund a výchozí hodnota UnspecifiedTransactionIsolationLevel je vhodná. Pro každou operaci můžete pomocí atributu OperationBehaviorAttribute určit, zda práce provedená v rámci metody by měla probíhat v rozsahu oboru transakce podle hodnoty atributu TransactionScopeRequired . V tomto případě je transakce použitá pro metodu Add stejná jako povinná příchozí transakce, která je tok z klienta, a transakce použitá pro Subtract metodu je buď stejná jako příchozí transakce, pokud byla tok z klienta, nebo nové implicitně a místně vytvořené transakce.

    [ServiceBehavior(  
        TransactionIsolationLevel = System.Transactions.IsolationLevel.Serializable,  
        TransactionTimeout = "00:00:45")]  
    public class CalculatorService : ICalculator  
    {  
        [OperationBehavior(TransactionScopeRequired = true)]  
        public double Add(double n1, double n2)  
        {  
            // Perform transactional operation  
            RecordToLog($"Adding {n1} to {n2}");
            return n1 + n2;  
        }  
    
        [OperationBehavior(TransactionScopeRequired = true)]  
        public double Subtract(double n1, double n2)  
        {  
            // Perform transactional operation  
            RecordToLog($"Subtracting {n2} from {n1}");
            return n1 - n2;  
        }  
    
        private static void RecordToLog(string recordText)  
        {  
            // Database operations omitted for brevity  
            // This is where the transaction provides specific benefit  
            // - changes to the database will be committed only when  
            // the transaction completes.  
        }  
    }  
    
  3. Nakonfigurujte vazby v konfiguračním souboru, určete, že má být tok kontextu transakce, a protokoly, které se mají použít k tomu. Další informace naleznete v tématu ServiceModel Transaction Configuration. Konkrétně je typ vazby zadán v atributu elementu koncového binding bodu. Element <koncového bodu> obsahuje bindingConfiguration atribut, který odkazuje na konfiguraci vazby s názvem transactionalOleTransactionsTcpBinding, jak je znázorněno v následující ukázkové konfiguraci.

    <service name="CalculatorService">  
      <endpoint address="net.tcp://localhost:8008/CalcService"  
        binding="netTcpBinding"  
        bindingConfiguration="transactionalOleTransactionsTcpBinding"  
        contract="ICalculator"  
        name="OleTransactions_endpoint" />  
    </service>  
    

    Tok transakcí je povolen na úrovni konfigurace pomocí atributu transactionFlow a transakční protokol je určen pomocí transactionProtocol atributu, jak je znázorněno v následující konfiguraci.

    <bindings>  
      <netTcpBinding>  
        <binding name="transactionalOleTransactionsTcpBinding"  
          transactionFlow="true"  
          transactionProtocol="OleTransactions"/>  
      </netTcpBinding>  
    </bindings>  
    

Podpora více transakčních protokolů

  1. Pro zajištění optimálního výkonu byste měli použít protokol OleTransactions pro scénáře zahrnující klienta a službu napsanou pomocí technologie Windows Communication Foundation (WCF). Protokol WS-AtomicTransaction (WS-AT) je však užitečný pro scénáře, kdy je vyžadována interoperabilita se zásobníky protokolů třetích stran. Služby WCF můžete nakonfigurovat tak, aby přijímaly oba protokoly tím, že poskytuje více koncových bodů s odpovídajícími vazbami specifickými pro protokol, jak je znázorněno v následující ukázkové konfiguraci.

    <service name="CalculatorService">  
      <endpoint address="http://localhost:8000/CalcService"  
        binding="wsHttpBinding"  
        bindingConfiguration="transactionalWsatHttpBinding"  
        contract="ICalculator"  
        name="WSAtomicTransaction_endpoint" />  
      <endpoint address="net.tcp://localhost:8008/CalcService"  
        binding="netTcpBinding"  
        bindingConfiguration="transactionalOleTransactionsTcpBinding"  
        contract="ICalculator"  
        name="OleTransactions_endpoint" />  
    </service>  
    

    Transakční protokol je určen pomocí atributu transactionProtocol . Tento atribut však chybí v systému poskytnutém wsHttpBinding, protože tato vazba může používat pouze protokol WS-AT.

    <bindings>  
      <wsHttpBinding>  
        <binding name="transactionalWsatHttpBinding"  
          transactionFlow="true" />  
      </wsHttpBinding>  
      <netTcpBinding>  
        <binding name="transactionalOleTransactionsTcpBinding"  
          transactionFlow="true"  
          transactionProtocol="OleTransactions"/>  
      </netTcpBinding>  
    </bindings>  
    

Řízení dokončení transakce

  1. Ve výchozím nastavení operace WCF automaticky dokončí transakce, pokud nejsou vyvolány žádné neošetřené výjimky. Toto chování můžete upravit pomocí TransactionAutoComplete vlastnosti a SetTransactionComplete metody. Pokud je nutné provést operaci ve stejné transakci jako jiná operace (například debetní a kreditní operace), můžete zakázat chování automatického TransactionAutoComplete dokončování nastavením vlastnosti tak, jak false je znázorněno v následujícím Debit příkladu operace. Transakce, kterou Debit operace používá, není dokončena, dokud metoda s TransactionAutoComplete nastavenou vlastností true je volána, jak je znázorněno v operaci Credit1, nebo když SetTransactionComplete je volána metoda explicitně označit transakce jako dokončena, jak je znázorněno v operaci Credit2. Všimněte si, že dvě operace kreditu jsou zobrazeny pro ilustrace a že jedna operace kreditu by byla obvyklejší.

    [ServiceBehavior]  
    public class CalculatorService : IAccount  
    {  
        [OperationBehavior(  
            TransactionScopeRequired = true, TransactionAutoComplete = false)]  
        public void Debit(double n)  
        {  
            // Perform debit operation  
    
            return;  
        }  
    
        [OperationBehavior(  
            TransactionScopeRequired = true, TransactionAutoComplete = true)]  
        public void Credit1(double n)  
        {  
            // Perform credit operation  
    
            return;  
        }  
    
        [OperationBehavior(  
            TransactionScopeRequired = true, TransactionAutoComplete = false)]  
        public void Credit2(double n)  
        {  
            // Perform alternate credit operation  
    
            OperationContext.Current.SetTransactionComplete();  
            return;  
        }  
    }  
    
  2. Pro účely korelace transakcí nastavujte TransactionAutoComplete vlastnost tak, aby false vyžadovala použití relace vazby. Tento požadavek je určen vlastností SessionMode v objektu ServiceContractAttribute.

    [ServiceContract(SessionMode = SessionMode.Required)]  
    public interface IAccount  
    {  
        [OperationContract]  
        [TransactionFlow(TransactionFlowOption.Allowed)]  
        void Debit(double n);  
        [OperationContract]  
        [TransactionFlow(TransactionFlowOption.Allowed)]  
        void Credit1(double n);  
        [OperationContract]  
        [TransactionFlow(TransactionFlowOption.Allowed)]  
        void Credit2(double n);  
    }  
    

Řízení životnosti instance transakční služby

  1. WCF používá ReleaseServiceInstanceOnTransactionComplete vlastnost k určení, zda je podkladová instance služby vydána po dokončení transakce. Vzhledem k tomu, že toto výchozí nastavení je true, pokud není nakonfigurováno jinak, WCF vykazuje efektivní a předvídatelné chování aktivace za běhu. Volání služby v následné transakci jsou zajištěna nová instance služby bez zbytků stavu předchozí transakce. I když je to často užitečné, někdy můžete chtít zachovat stav v instanci služby nad rámec dokončení transakce. Příklady by byly v případě, že požadovaný stav nebo popisovače prostředků jsou nákladné načíst nebo rekonstituovat. Můžete to provést nastavením ReleaseServiceInstanceOnTransactionComplete vlastnosti na falsehodnotu . Při tomto nastavení bude instance a jakýkoli přidružený stav k dispozici při následných voláních. Při tomto použití pečlivě zvažte, kdy a jak budou stav a transakce vymazány a dokončeny. Následující ukázka ukazuje, jak to provést udržováním instance s proměnnou runningTotal .

    [ServiceBehavior(TransactionIsolationLevel = [ServiceBehavior(  
        ReleaseServiceInstanceOnTransactionComplete = false)]  
    public class CalculatorService : ICalculator  
    {  
        double runningTotal = 0;  
    
        [OperationBehavior(TransactionScopeRequired = true)]  
        public double Add(double n)  
        {  
            // Perform transactional operation  
            RecordToLog($"Adding {n} to {runningTotal}");
            runningTotal = runningTotal + n;  
            return runningTotal;  
        }  
    
        [OperationBehavior(TransactionScopeRequired = true)]  
        public double Subtract(double n)  
        {  
            // Perform transactional operation  
            RecordToLog($"Subtracting {n} from {runningTotal}");
            runningTotal = runningTotal - n;  
            return runningTotal;  
        }  
    
        private static void RecordToLog(string recordText)  
        {  
            // Database operations omitted for brevity  
        }  
    }  
    

    Poznámka:

    Vzhledem k tomu, že životnost instance je chování, které je interní pro službu a řídí se ServiceBehaviorAttribute prostřednictvím vlastnosti, není nutné provádět žádné změny konfigurace služby nebo kontraktu služby k nastavení chování instance. Kromě toho drát nebude obsahovat žádnou reprezentaci.