Cara: Membuat Layanan Transaksional
Sampel ini menunjukkan berbagai aspek dalam membuat layanan transaksional dan penggunaan transaksi yang dimulai klien untuk mengoordinasikan operasi layanan.
Membuat layanan transaksi
Buat kontrak layanan dan anotasi operasi dengan pengaturan yang diinginkan dari enumerasi TransactionFlowOption untuk menentukan persyaratan transaksi masuk. Perhatikan bahwa Anda juga bisa menempatkan TransactionFlowAttribute pada kelas layanan yang sedang diimplementasikan. Hal ini memungkinkan untuk satu implementasi antarmuka untuk menggunakan pengaturan transaksi ini, bukan setiap implementasi.
[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); }
Buat kelas implementasi, dan gunakan ServiceBehaviorAttribute untuk secara opsional menentukan TransactionIsolationLevel dan TransactionTimeout. Anda harus mencatat bahwa dalam banyak kasus, pengaturan default TransactionTimeout 60 detik dan default TransactionIsolationLevel pada
Unspecified
itu sesuai. Untuk setiap operasi, Anda bisa menggunakan atribut OperationBehaviorAttribute guna menentukan apakah pekerjaan yang dijalankan dalam metode harus terjadi dalam cakupan transaksi sesuai dengan nilai atribut TransactionScopeRequired. Dalam hal ini, transaksi yang digunakan untuk metodeAdd
ini sama dengan transaksi masuk wajib yang mengalir dari klien, dan transaksi yang digunakan untuk metodeSubtract
ini sama dengan transaksi masuk jika transaksi tersebut mengalir dari klien, atau transaksi baru yang dibuat secara implisit dan lokal.[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. } }
Konfigurasikan pengikatan dalam file konfigurasi, tentukan bahwa konteks transaksi harus dialirkan, dan protokol yang akan digunakan untuk melakukannya. Untuk informasi selengkapnya, lihat Konfigurasi Transaksi ServiceModel. Khususnya, jenis pengikatan ditentukan dalam atribut
binding
elemen titik akhir. Elemen <endpoint> berisi atributbindingConfiguration
yang mereferensikan konfigurasi pengikatan bernamatransactionalOleTransactionsTcpBinding
, seperti yang ditunjukkan dalam konfigurasi sampel berikut.<service name="CalculatorService"> <endpoint address="net.tcp://localhost:8008/CalcService" binding="netTcpBinding" bindingConfiguration="transactionalOleTransactionsTcpBinding" contract="ICalculator" name="OleTransactions_endpoint" /> </service>
Alur transaksi diaktifkan pada tingkat konfigurasi menggunakan atribut
transactionFlow
, dan protokol transaksi ditentukan menggunakan atributtransactionProtocol
, seperti yang ditunjukkan dalam konfigurasi berikut.<bindings> <netTcpBinding> <binding name="transactionalOleTransactionsTcpBinding" transactionFlow="true" transactionProtocol="OleTransactions"/> </netTcpBinding> </bindings>
Mendukung beberapa protokol transaksi
Untuk performa yang optimal, Anda harus menggunakan protokol OleTransactions untuk skenario yang melibatkan klien dan layanan yang ditulis menggunakan Windows Communication Foundation (WCF). Namun, protokol WS-AtomicTransaction (WS-AT) berguna untuk skenario ketika interoperabilitas dengan tumpukan protokol pihak ketiga diperlukan. Anda dapat mengonfigurasi layanan WCF untuk menerima kedua protokol dengan menyediakan beberapa titik akhir bersama pengikatan khusus protokol yang sesuai, seperti yang ditunjukkan dalam konfigurasi sampel berikut.
<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>
Protokol transaksi ditentukan menggunakan atribut
transactionProtocol
. Namun, atribut ini tidak ada dariwsHttpBinding
yang disediakan sistem, karena pengikatan ini hanya dapat menggunakan protokol WS-AT.<bindings> <wsHttpBinding> <binding name="transactionalWsatHttpBinding" transactionFlow="true" /> </wsHttpBinding> <netTcpBinding> <binding name="transactionalOleTransactionsTcpBinding" transactionFlow="true" transactionProtocol="OleTransactions"/> </netTcpBinding> </bindings>
Mengontrol penyelesaian transaksi
Secara default, operasi WCF otomatis menyelesaikan transaksi jika tidak ada pengecualian yang tidak ditangani dan dilemparkan. Anda dapat mengubah perilaku ini menggunakan properti TransactionAutoComplete dan metode SetTransactionComplete. Saat operasi diperlukan untuk terjadi dalam transaksi yang sama dengan operasi lain (misalnya, operasi debit dan kredit), Anda dapat menonaktifkan perilaku lengkapi otomatis dengan mengatur properti TransactionAutoComplete ke
false
seperti yang ditunjukkan dalam contoh operasiDebit
berikut. Transaksi yang digunakan operasiDebit
tidak selesai hingga metode dengan properti TransactionAutoComplete yang diatur ketrue
dipanggil, seperti yang ditunjukkan dalam operasiCredit1
, atau ketika metode SetTransactionComplete dipanggil untuk secara eksplisit menandai transaksi sebagai selesai, seperti yang ditunjukkan dalam operasiCredit2
. Perhatikan bahwa dua operasi kredit ditampilkan sebagai ilustrasi, dan bahwa operasi kredit tunggal akan lebih umum.[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; } }
Untuk tujuan korelasi transaksi, mengatur properti TransactionAutoComplete ke
false
memerlukan penggunaan pengikatan sesi. Persyaratan ini ditentukan dengan propertiSessionMode
pada 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); }
Mengontrol masa pakai instans layanan transaksional
WCF menggunakan properti ReleaseServiceInstanceOnTransactionComplete untuk menentukan apakah instans layanan yang mendasar dirilis saat transaksi selesai. Karena pengaturan ini default ke
true
, kecuali dikonfigurasi sebaliknya, WCF menunjukkan perilaku aktivasi "just-in-time" yang efisien dan bisa diprediksi. Panggilan ke layanan pada transaksi berikutnya menjamin instans layanan baru tanpa sisa-sisa status transaksi sebelumnya. Meskipun hal ini sering berguna, kadang-kadang Anda mungkin ingin mempertahankan status dalam instans layanan di luar penyelesaian transaksi. Contohnya ketika status atau handel ke sumber daya yang diperlukan bersifat mahal untuk diambil atau disusun ulang. Anda dapat melakukannya dengan mengatur properti ReleaseServiceInstanceOnTransactionComplete kefalse
. Dengan pengaturan ini, instans dan status terkait akan tersedia pada panggilan berikutnya. Saat menggunakan ini, berikan pertimbangan yang cermat tentang waktu dan cara status dan transaksi akan dibersihkan dan diselesaikan. Sampel berikut menunjukkan cara melakukan ini dengan mempertahankan instans yang memiliki variabelrunningTotal
.[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 } }
Catatan
Karena masa pakai instans adalah perilaku internal bagi layanan, dan dikontrol melalui properti ServiceBehaviorAttribute, tidak ada modifikasi pada konfigurasi layanan atau kontrak layanan yang diperlukan untuk mengatur perilaku instans. Selain itu, kabel tidak akan berisi representasi ini.