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
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); }
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
Unspecified
TransactionIsolationLevel 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 metoduAdd
stejná jako povinná příchozí transakce, která je tok z klienta, a transakce použitá proSubtract
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. } }
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> obsahujebindingConfiguration
atribut, který odkazuje na konfiguraci vazby s názvemtransactionalOleTransactionsTcpBinding
, 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ů
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émwsHttpBinding
, 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
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ímDebit
příkladu operace. Transakce, kterouDebit
operace používá, není dokončena, dokud metoda s TransactionAutoComplete nastavenou vlastnostítrue
je volána, jak je znázorněno v operaciCredit1
, nebo když SetTransactionComplete je volána metoda explicitně označit transakce jako dokončena, jak je znázorněno v operaciCredit2
. 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; } }
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
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 nafalse
hodnotu . 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ěnnourunningTotal
.[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.