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
查看更多关于WCF服务编程读书笔记(7):事务的详细内容...