Bagikan melalui


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

  1. 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);  
    }  
    
  2. 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 metode Add ini sama dengan transaksi masuk wajib yang mengalir dari klien, dan transaksi yang digunakan untuk metode Subtract 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.  
        }  
    }  
    
  3. 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 atribut bindingConfiguration yang mereferensikan konfigurasi pengikatan bernama transactionalOleTransactionsTcpBinding, 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 atribut transactionProtocol, seperti yang ditunjukkan dalam konfigurasi berikut.

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

Mendukung beberapa protokol transaksi

  1. 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 dari wsHttpBinding 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

  1. 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 operasi Debit berikut. Transaksi yang digunakan operasi Debit tidak selesai hingga metode dengan properti TransactionAutoComplete yang diatur ke true dipanggil, seperti yang ditunjukkan dalam operasi Credit1, atau ketika metode SetTransactionComplete dipanggil untuk secara eksplisit menandai transaksi sebagai selesai, seperti yang ditunjukkan dalam operasi Credit2. 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;  
        }  
    }  
    
  2. Untuk tujuan korelasi transaksi, mengatur properti TransactionAutoComplete ke false memerlukan penggunaan pengikatan sesi. Persyaratan ini ditentukan dengan properti SessionMode 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

  1. 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 ke false. 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 variabel 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  
        }  
    }  
    

    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.