zoukankan      html  css  js  c++  java
  • WCF服务编程读书笔记(7):事务

    Example 7-1. Explicit transaction management

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.Diagnostics;
    using System.Runtime.Serialization;
    using System.ServiceModel.Dispatcher;
    using System.ServiceModel.Description;
    using System.Collections.ObjectModel;
    using System.Data;
    using System.Data.SqlClient;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            void MyMethod();
        }
    
    
        class MyService : IMyContract
        {
            public void MyMethod()
            {
                //Avoid this programming model
    
                string connectionString = "";
    
                IDbConnection conn = new SqlConnection(connectionString);
                conn.Open();
    
                IDbCommand comm = new SqlCommand();
                comm.Connection = conn;
    
                IDbTransaction trans = conn.BeginTransaction(); //Enlisting
                comm.Transaction = trans;
    
                try
                {
                    // Interact with database here, then commit the transaction
                    trans.Commit();
                }
                catch
                {
                    trans.Rollback(); // Abort transaction
                }
                finally
                {
                    conn.Close();
                    comm.Dispose();
                    trans.Dispose();
                }
            }
        }
    }
    View Code

    Example 7-2. Configuring for the Client/Service transaction mode

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod();
        }
    
    
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
                Transaction transaction = Transaction.Current;
                Debug.Assert(transaction != null);
            }
        }
    }
    View Code

    Example 7-3. The BindingRequirementAttribute

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel.Description;
    using System.ServiceModel;
    using System.Collections.ObjectModel;
    using System.ServiceModel.Channels;
    
    namespace WCFServiceProgramming.Library
    {
        class BindingRequirementAttribute : Attribute, IServiceBehavior
        {
            public bool TransactionFlowEnabled { get; set; }
    
            public void AddBindingParameters(ServiceDescription description, ServiceHostBase host, 
                Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
            {           
            }
    
            public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase host)
            {  
            }
    
            public void Validate(ServiceDescription description, ServiceHostBase host)
            {
                if (TransactionFlowEnabled == false)
                {
                    return;
                }
    
                foreach (ServiceEndpoint endpoint in description.Endpoints)
                {
                    Exception exception = new InvalidOperationException();
    
                    foreach (OperationDescription operation in endpoint.Contract.Operations)
                    {
                        foreach (IOperationBehavior behavior in operation.Behaviors)
                        {
                            if (behavior is TransactionFlowAttribute)
                            {
                                TransactionFlowAttribute attribute = behavior as TransactionFlowAttribute;
                                if (attribute.Transactions == TransactionFlowOption.Allowed)
                                {
                                    if (endpoint.Binding is NetTcpBinding)
                                    {
                                        NetTcpBinding tcpBinding = endpoint.Binding as NetTcpBinding;
                                        if (tcpBinding.TransactionFlow == false)
                                        {
                                            throw exception;
                                        }
                                        break;
                                    }
    
                                    // Similar checks for the rest of the transaction-aware bindings
    
                                    throw new InvalidOperationException();
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    View Code

    Example 7-4. Configuring for the Client transaction mode

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Mandatory)]
            void MyMethod();
        }
    
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
                Transaction transaction = Transaction.Current;
                Debug.Assert(transaction.TransactionInformation.DistributedIdentifier != Guid.Empty);
    
            }
        }
    }
    View Code

    Example 7-5. Configuring for the Service transaction mode

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            void MyMethod();
        }
    
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
                Transaction transaction = Transaction.Current;
                Debug.Assert(transaction.TransactionInformation.DistributedIdentifier == Guid.Empty);
    
            }
        }
    }
    View Code

    Example 7-6. Configuring for the None transaction mode

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            void MyMethod();
        }
    
        class MyService : IMyContract
        {
            public void MyMethod()
            {
                Transaction transaction = Transaction.Current;
                Debug.Assert(transaction == null);
    
            }
        }
    }
    View Code

    Example 7-7. Using TransactionScope

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            void MyMethod();
        }
    
        class MyService : IMyContract
        {
            public void MyMethod()
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    // Perform transaction work here
                    // No errors - commit transaction
                    scope.Complete();
                }
    
            }
        }
    }
    View Code

    Example 7-8. TransactionScope and error handling

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            void MyMethod();
        }
    
        class MyService : IMyContract
        {
            public void MyMethod()
            {
                try
                {
                    using (TransactionScope scope = new TransactionScope())
                    {
                        // Perform transaction work here
                        // No errors - commit transaction
                        scope.Complete();
                    }
                }
                catch (TransactionAbortedException ex)
                {
                    Trace.WriteLine(ex.Message);
                }
                catch (Exception ex) // Any other exception took place
                {
                    Trace.WriteLine("Cannot complete transaction");
                    throw ex;
                }
            }
        }
    }
    View Code

    Example 7-9. Direct scope nesting

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            void MyMethod();
        }
    
        class MyService : IMyContract
        {
            public void MyMethod()
            {
                using (TransactionScope scope1 = new TransactionScope())
                {
                    using (TransactionScope scope2 = new TransactionScope())
                    {
                        scope2.Complete();
                    }
    
                    scope1.Complete();
                }
            }
        }
    }
    View Code

    Example 7-10. Indirect scope nesting

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            void MyMethod();
        }
    
        class MyService : IMyContract
        {
            public void MyMethod()
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    // Perform transaction work here
    
                    SomeMethod();
                    scope.Complete();
                }
            }
    
            private static void SomeMethod()
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    // Perform transaction work here
    
                    scope.Complete();
                }
            }
        }
    }
    View Code

    Example 7-11. Scope nesting inside a service method

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            void MyMethod();
        }
    
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    // Perform transaction work here
                    scope.Complete();
                }
            }
        }
    }
    View Code

    Example 7-12. Using TransactionScopeOption.Required in a downstream class

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            void MyMethod();
        }
    
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
                MyClass obj = new MyClass();
                obj.SomeMethod();
            }
        }
    
        class MyClass
        {
            public void SomeMethod()
            {
                using (TransactionScope scope = 
                    new TransactionScope(TransactionScopeOption.Required))
                {
                    // Do some work then 
                    scope.Complete();
                }
            }
        }
    }
    View Code

    Example 7-13. Using TransactionScopeOption.Suppress

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            void MyMethod();
        }
    
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
                try
                {
                    // Start of nontransactional section
    
                    using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Suppress))
                    {
                        // Do nontransactional work here
                    }
    
                    // Restores ambient transaction here
                }
                catch
                { }
            }
        }
    }
    View Code

    Example 7-14. Using TransactionScope to call services in a single transaction(Service Side)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Diagnostics;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Library
    {
        /////////////////////////////////// Service Side //////////////////////////////////////
    
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod();
        }
    
        [ServiceContract]
        public interface IMyOtherContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Mandatory)]
            void MyOtherMethod();
        }
    
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
            }
        }
    
        class MyOtherService : IMyOtherContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyOtherMethod()
            {
            }
        }
    }
    View Code

    Example 7-14. Using TransactionScope to call services in a single transaction(Client Side)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using WCFServiceProgramming.Library;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Client
    {
        ////////////////////////////////// Client Side /////////////////////////////////
        class MyContractClient : ClientBase<IMyContract>, IMyContract
        {
            public void MyMethod()
            {
                Channel.MyMethod();
            }
        }
    
        class MyOtherContractClient : ClientBase<IMyOtherContract>, IMyOtherContract
        {
            public void MyOtherMethod()
            {
                Channel.MyOtherMethod();
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    MyContractClient proxy1 = new MyContractClient();
                    proxy1.MyMethod();
                    proxy1.Close();
    
                    MyOtherContractClient proxy2 = new MyOtherContractClient();
                    proxy2.MyOtherMethod();
                    proxy2.Close();
    
                    scope.Complete();
                }
    
                using (MyContractClient proxy3 = new MyContractClient())
                using (MyOtherContractClient proxy4 = new MyOtherContractClient())
                using (TransactionScope scope = new TransactionScope())
                {
                    proxy3.MyMethod();
                    proxy4.MyOtherMethod();
    
                    scope.Complete();
                }
            }
        }
    }
    View Code

    Example 7-15. Implementing a transactional service

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Runtime.Serialization;
    
    namespace WCFServiceProgramming.Library
    {
        [DataContract]
        class Param
        { }
    
        [ServiceContract]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod();
        }
    
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
        class MyService : IMyContract, IDisposable
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod(Param stateIdentifier)
            {
                GetState(stateIdentifier);
                DoWork();
                SaveState(stateIdentifier);
            }
    
            void GetState(Param stateIdentifier)
            { }
    
            void DoWork()
            { }
    
            void SaveState(Param stateIdentifier)
            { }
    
            public void Dispose()
            { }
        }
    }
    View Code

    Example 7-16. Per-session yet per-call transactional service

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Runtime.Serialization;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract(SessionMode = SessionMode.Required)]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod();
        }
    
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
            }
        }
    }
    View Code

    Example 7-17. Per-session transactional service

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Runtime.Serialization;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract(SessionMode = SessionMode.Required)]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod();
        }
    
        [ServiceBehavior(ReleaseServiceInstanceOnTransactionComplete = false)]
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
            }
        }
    }
    View Code

    Example 7-18. State-aware, transactional per-session service

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Runtime.Serialization;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract(SessionMode = SessionMode.Required)]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod();
        }
    
        [ServiceBehavior(ReleaseServiceInstanceOnTransactionComplete = false)]
        class MyService : IMyContract, IDisposable
        {
            readonly string _stateIdentifier;
    
            public MyService()
            {
                InitializeState();
                _stateIdentifier = OperationContext.Current.SessionId;
                SaveState();
            }
    
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
                GetState();
                Dowork();
                SaveState();
            }
    
            public void Dispose()
            {
                RemoveState();
            }
    
            // Helper methods
    
            private void InitializeState()
            {
            }
    
            private void GetState()
            {
            }
    
            private void Dowork()
            {
            }
    
            private void SaveState()
            {
            }
    
            private void RemoveState()
            {
            }
        }
    }
    View Code

    Example 7-19. Using volatile resource managers to achieve stateful per-session transactional service

    Example 7-20. Launching concurrent transactions

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using WCFServiceProgramming.Library;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Client
    {
        class MyContractClient : ClientBase<IMyContract>, IMyContract
        {
            public void MyMethod()
            {
                Channel.MyMethod();
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                using (TransactionScope scope1 = new TransactionScope())
                {
                    MyContractClient proxy = new MyContractClient();
                    proxy.MyMethod();
    
                    using (TransactionScope scope2 = new TransactionScope(TransactionScopeOption.RequiresNew))
                    {
                        proxy.MyMethod();
                        scope2.Complete();
                    }
    
                    proxy.Close();
                    scope1.Complete();
                }
            }
        }
    }
    View Code

    Example 7-21. Setting TransactionAutoComplete to false

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Runtime.Serialization;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract(SessionMode = SessionMode.Required)]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod1();
    
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod2();
        }
    
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true, 
                TransactionAutoComplete = false)]
            public void MyMethod1()
            {
            }
    
            [OperationBehavior(TransactionScopeRequired = true,
                TransactionAutoComplete = false)]
            public void MyMethod2()
            {
            }
        }
    }
    View Code

    Example 7-22. Hybrid per-session service

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Runtime.Serialization;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract(SessionMode = SessionMode.Required)]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod1();
    
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod2();
        }
    
        [ServiceBehavior(TransactionAutoCompleteOnSessionClose = true)]
        class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true, 
                TransactionAutoComplete = false)]
            public void MyMethod1()
            {
            }
    
            [OperationBehavior(TransactionScopeRequired = true,
                TransactionAutoComplete = false)]
            public void MyMethod2()
            {
            }
        }
    }
    View Code

    Example 7-23. State-aware singleton(Service Side)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Runtime.Serialization;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract(SessionMode = SessionMode.Required)]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod();
        }
    
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
        class MyService : IMyContract
        {
            readonly static string _stateIdentifier = typeof(MyService).GUID.ToString();
    
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
                GetState();
                Dowork();
                SaveState();
            }
    
            private void GetState()
            {
            }
    
            private void Dowork()
            {
            }
    
            public void SaveState()
            {
                // Use _stateIdentifier to save state
            }
    
            public void RemoveState()
            {
                // Use _stateIdentifier to remove the state from the resource manager
            }
        }
    }
    View Code

    Example 7-23. State-aware singleton(Hosting)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using WCFServiceProgramming.Library;
    using System.ServiceModel;
    using System.ServiceModel.Description;
    
    namespace WCFServiceProgramming.Host
    {
        class Program
        {
            static void Main(string[] args)
            {
                MyService singleton = new MyService();
                singleton.SaveState();
    
                ServiceHost host = new ServiceHost(singleton);
                host.Open();
    
                // Some blocking calls
    
                host.Close();
                singleton.RemoveState();
            }
        }
    }
    View Code

    Example 7-24. Achieving stateful singleton transactional service (Service Side)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Runtime.Serialization;
    using System.Diagnostics;
    
    namespace WCFServiceProgramming.Library
    {
        //////////////////////////////// Service Side /////////////////////////////////
    
        [ServiceContract(SessionMode = SessionMode.Required)]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod();
        }
    
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, 
            ReleaseServiceInstanceOnTransactionComplete = false)]
        public class MyService : IMyContract
        {
            int _counter = 0;
    
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
                _counter++;
                Trace.WriteLine("Counter: " + _counter);
            }
        }
    }
    View Code

    Example 7-24. Achieving stateful singleton transactional service (Client Side)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using WCFServiceProgramming.Library;
    using System.Transactions;
    
    namespace WCFServiceProgramming.Client
    {
        ////////////////////////////// Client Side /////////////////////////////////
    
        class MyContractClient : ClientBase<IMyContract>, IMyContract
        {
            public void MyMethod()
            {
                Channel.MyMethod();
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                using (TransactionScope scope1 = new TransactionScope())
                {
                    MyContractClient proxy = new MyContractClient();
                    proxy.MyMethod();
                    proxy.Close();
                    scope1.Complete();
                }
    
                using (TransactionScope scope2 = new TransactionScope())
                {
                    MyContractClient proxy = new MyContractClient();
                    proxy.MyMethod();
                    proxy.Close();
                    scope2.Complete();
                }
    
                using (TransactionScope scope3 = new TransactionScope())
                {
                    MyContractClient proxy = new MyContractClient();
                    proxy.MyMethod();
                    proxy.Close();
                    scope3.Complete();
                }
            }
        }
    }
    View Code

    Example 7-25. Configuring the callback for Service transaction

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Diagnostics;
    
    namespace WCFServiceProgramming.Library
    {
        public interface IMyContractCallback
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Mandatory)]
            void OnCallback();
        }
    
        class MyClient : IMyContractCallback
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void OnCallback()
            {
                Transaction transaction = Transaction.Current;
                Debug.Assert(transaction.TransactionInformation.
                    DistributedIdentifier != Guid.Empty);
            }
        }
    }
    View Code

    Example 7-26. Out-of-band callbacks

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Runtime.Serialization;
    using System.Diagnostics;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract(SessionMode = SessionMode.Required)]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod();
        }
    
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
        public class MyService : IMyContract
        {
            static List<IMyContractCallback> _callbacks = new List<IMyContractCallback>();
    
            public void MyMethod()
            {
                IMyContractCallback callback = 
                    OperationContext.Current.GetCallbackChannel<IMyContractCallback>();
    
                if (_callbacks.Contains(callback) == false)
                {
                    _callbacks.Add(callback);
                }
            }
    
            public static void CallClients()
            {
                Action<IMyContractCallback> invoke = delegate(IMyContractCallback callback)
                {
                    using (TransactionScope scope = new TransactionScope())
                    {
                        callback.OnCallback();
                        scope.Complete();
                    }
                };
    
                _callbacks.ForEach(invoke);
            }
        }
    }
    View Code

    //Out-of-band callbacks:
    MyService.CallClients( );

    Example 7-27. Configuring for transactional callbacks(Service Side)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Transactions;
    using System.Runtime.Serialization;
    using System.Diagnostics;
    
    namespace WCFServiceProgramming.Library
    {
        [ServiceContract(CallbackContract = typeof(IMyContractCallback))]
        public interface IMyContract
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void MyMethod();
        }
    
        public interface IMyContractCallback
        {
            [OperationContract]
            [TransactionFlow(TransactionFlowOption.Allowed)]
            void OnCallback();
        }
    
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, 
            ConcurrencyMode = ConcurrencyMode.Reentrant, 
            ReleaseServiceInstanceOnTransactionComplete = false)]
        public class MyService : IMyContract
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void MyMethod()
            {
                Trace.WriteLine("Service ID: " + 
                    Transaction.Current.TransactionInformation.DistributedIdentifier);
    
                IMyContractCallback callback = 
                    OperationContext.Current.GetCallbackChannel<IMyContractCallback>();
    
                callback.OnCallback();
            }
        }
    }
    View Code

    Example 7-27. Configuring for transactional callbacks(Client Side)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using WCFServiceProgramming.Library;
    using System.Transactions;
    using System.Diagnostics;
    
    namespace WCFServiceProgramming.Client
    {
        class MyClient : IMyContractCallback
        {
            [OperationBehavior(TransactionScopeRequired = true)]
            public void OnCallback()
            {
                Trace.WriteLine("OnCallback ID: " +
                    Transaction.Current.TransactionInformation.DistributedIdentifier);
            }
        }
    
        class MyContractClient : ClientBase<IMyContract>, IMyContract
        {
            private InstanceContext _context;
    
            public MyContractClient(InstanceContext context)
            {
                this._context = context;
            }
            public void MyMethod()
            {
                Channel.MyMethod();
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                MyClient client = new MyClient();
                InstanceContext context = new InstanceContext(client);
                MyContractClient proxy = new MyContractClient(context);
    
                using (TransactionScope scope = new TransactionScope())
                {
                    proxy.MyMethod();
    
                    Trace.WriteLine("Client ID: " + 
                        Transaction.Current.TransactionInformation.DistributedIdentifier);
    
                    scope.Complete();
                }
    
                proxy.Close();
            }
        }
    }
    View Code
  • 相关阅读:
    120所国家重点建设大学(211工程和教育部直属)[国家一类本科大学]详细情况一览表
    VC画线几个常见方法
    中国地学35个国家重点实验室分布一览
    可执行文件加入Linux默认路径的办法
    SVN 常用命令 客户端
    ls(list) linux 功能说明
    Vim
    Linux添加FTP用户并设置权限
    tar [cxtzjvfpPN] 文件与目录
    linux etc/passwd 有关
  • 原文地址:https://www.cnblogs.com/thlzhf/p/2782990.html
Copyright © 2011-2022 走看看