Example 9-1. Implementing and consuming a queued service
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace WCFServiceProgramming.Library { [ServiceContract] public interface IMyContract { [OperationContract(IsOneWay = true)] void MyMethod(); } public class MyService : IMyContract { public void MyMethod() { } } }
Example 9-2. Disabling MSMQ security
<?xml version="1.0"?> <configuration> <system.web> <compilation debug="false" targetFramework="4.0" /> </system.web> <system.serviceModel> <services> <service name=""> <endpoint name="MyServiceQueue" address="net.msmq://localhost/private/MyServiceQueue" binding="netMsmqBinding" bindingConfiguration="NoMSMQSecurity" contract="IMyContract"/> </service> </services> <bindings> <netMsmqBinding> <binding name="NoMSMQSecurity"> <security mode="None"></security> </binding> </netMsmqBinding> </bindings> </system.serviceModel> </configuration>
Example 9-3. Verifying a queue on the host
using System; using System.Collections.Generic; using System.Linq; using System.Text; using WCFServiceProgramming.Library; using System.ServiceModel; using System.Messaging; namespace WCFServiceProgramming.Host { class Program { static void Main(string[] args) { ServiceHost host = new ServiceHost(typeof(MyService)); if (MessageQueue.Exists(@".\privates$\MyServiceQueue") == false) { MessageQueue.Create(@".\private$\MyServiceQueue", true); } host.Open(); } } }
Example 9-4. Creating the queues in ServiceHost<T>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Description; using WCFServiceProgramming.Library; using System.Messaging; namespace WCFServiceProgramming.Host { public class ServiceHost<T> : ServiceHost { protected override void OnOpening() { foreach (ServiceEndpoint endpoint in Description.Endpoints) { QueuedServiceHelper.VerifyQueue(endpoint); } base.OnOpening(); } } public static class QueuedServiceHelper { public static void VerifyQueue(ServiceEndpoint endpoint) { if (endpoint.Binding is NetMsmqBinding) { string queue = GetQueueFromUri(endpoint.Address.Uri); if (MessageQueue.Exists(queue) == false) { MessageQueue.Create(queue, true); } } } static string GetQueueFromUri(Uri uri) { return @".\privates$\" + uri.LocalPath.ToString(); } } }
Example 9-5. Verifying the queue by the client
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using WCFServiceProgramming.Library; using System.Messaging; namespace WCFServiceProgramming.Client { class MyContractClient : ClientBase<IMyContract>, IMyContract { public void MyMethod() { Channel.MyMethod(); } } class Program { static void Main(string[] args) { if (MessageQueue.Exists(@".\private$\MyServiceQueue") == false) { MessageQueue.Create(@".\private$\MyServiceQueue", true); } MyContractClient proxy = new MyContractClient(); proxy.MyMethod(); proxy.Close(); } } }
Example 9-6. Extending QueuedServiceHelper to verify the queue on the client side
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Description; namespace WCFServiceProgramming { public static class QueuedServiceHelper { public static void VerifyQueue<T>(string endpointName) where T : class { ChannelFactory<T> factory = new ChannelFactory<T>(endpointName); VerifyQueue(factory.Endpoint); } public static void VerifyQueue<T>() where T : class { VerifyQueue<T>(""); } // Same as Example 9-4 public static void VerifyQueue(ServiceEndpoint endpoint) { // ... } } }
Example 9-7. Purging the queues on host shutdown during debugging
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Description; using WCFServiceProgramming.Library; using System.Messaging; using System.Diagnostics; namespace WCFServiceProgramming.Host { public static class QueuedServiceHelper { public static void PurgeQueue(ServiceEndpoint endpoint) { if (endpoint.Binding is NetMsmqBinding) { string queueName = GetQueueFromUri(endpoint.Address.Uri); if (MessageQueue.Exists(queueName) == true) { MessageQueue queue = new MessageQueue(queueName); queue.Purge(); } } } static string GetQueueFromUri(Uri uri) { return @".\privates$\" + uri.LocalPath.ToString(); } } public class ServiceHost<T> : ServiceHost { protected override void OnClosing() { PurgeQueues(); // More cleanup if necessary base.OnClosing(); } [Conditional("DEBUG")] void PurgeQueues() { foreach (ServiceEndpoint endpoint in Description.Endpoints) { QueuedServiceHelper.PurgeQueue(endpoint); } } // More members } }
Example 9-8. Participating in the playback 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 { [ServiceContract] public interface IMyContract { [OperationContract(IsOneWay = true)] void MyMethod(); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] public class MyService : IMyContract { [OperationBehavior(TransactionScopeRequired = true)] public void MyMethod() { Transaction transaction = Transaction.Current; Debug.Assert(transaction.TransactionInformation.DistributedIdentifier != Guid.Empty); } } }
Example 9-9. Ignoring the playback 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 { [ServiceContract] public interface IMyContract { [OperationContract(IsOneWay = true)] void MyMethod(); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] public class MyService : IMyContract { public void MyMethod() { Transaction transaction = Transaction.Current; Debug.Assert(transaction == null); } } }
Example 9-10. Using a new 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 { [ServiceContract] public interface IMyContract { [OperationContract(IsOneWay = true)] void MyMethod(); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] public class MyService : IMyContract { public void MyMethod() { using (TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew)) { // ... scope.Complete(); } } } }
Example 9-11. Nontransactional client of a sessionless queued endpoint
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using WCFServiceProgramming.Library; using System.Messaging; 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 scope = new TransactionScope(TransactionScopeOption.Suppress)) { MyContractClient proxy = new MyContractClient(); proxy.MyMethod(); // Message posts to queue here proxy.MyMethod(); // Message posts to queue here proxy.Close(); } } } }
Example 9-12. Transactional client of a queued sessionless endpoint
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using WCFServiceProgramming.Library; using System.Messaging; 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 scope = new TransactionScope()) { MyContractClient proxy = new MyContractClient(); proxy.MyMethod(); // Message posts to queue here proxy.MyMethod(); // Message posts to queue here proxy.Close(); scope.Complete(); } } } }
Example 9-13. Implementing a sessionful queued service
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.Transactions; using System.Diagnostics; namespace WCFServiceProgramming.Library { [ServiceContract(SessionMode = SessionMode.Required)] public interface IMyContract { [OperationContract(IsOneWay = true)] void MyMethod1(); [OperationContract(IsOneWay = true)] void MyMethod2(); [OperationContract(IsOneWay = true)] void MyMethod3(); } public class MyService : IMyContract { [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)] public void MyMethod1() { } [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false)] public void MyMethod2() { } [OperationBehavior(TransactionScopeRequired = true)] public void MyMethod3() { } } }
Example 9-14. Transactional queued singleton
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.Transactions; using System.Diagnostics; namespace WCFServiceProgramming.Library { [ServiceContract(SessionMode = SessionMode.NotAllowed)] public interface IMyContract { [OperationContract(IsOneWay = true)] void MyMethod(); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ReleaseServiceInstanceOnTransactionComplete = false)] public class MySingleton : IMyContract, IDisposable { [OperationBehavior(TransactionScopeRequired = true)] public void MyMethod() { } public void Dispose() { } } }
Example 9-15. Verifying a custom DLQ
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using System.ServiceModel.Description; using WCFServiceProgramming.Library; using System.Messaging; using System.Diagnostics; namespace WCFServiceProgramming.Host { public static class QueuedServiceHelper { public static void VerifyQueue(ServiceEndpoint endpoint) { if (endpoint.Binding is NetMsmqBinding) { string queueName = GetQueueFromUri(endpoint.Address.Uri); if (MessageQueue.Exists(queueName) == false) { MessageQueue.Create(queueName, true); } NetMsmqBinding binding = endpoint.Binding as NetMsmqBinding; if (binding.DeadLetterQueue == DeadLetterQueue.Custom) { Debug.Assert(binding.CustomDeadLetterQueue != null); string dlq = GetQueueFromUri(binding.CustomDeadLetterQueue); if (MessageQueue.Exists(dlq) == false) { MessageQueue.Create(dlq, true); } } } } static string GetQueueFromUri(Uri uri) { return @".\privates$\" + uri.LocalPath.ToString(); } } }
Example 9-16. DLQ service config file
Example 9-17. Obtaining the MsmqMessageProperty
Example 9-18. Implementing a DLQ service
Example 9-19. Poison message handling on MSMQ 4
Example 9-20. Configuring a poison message service
Example 9-21. A simple response service
Example 9-22. The ResponseContext class
Example 9-23. Client-side programming with a response service
Example 9-24. Service-side programming with a response service
Example 9-25. Implementing a response service
Example 9-26. The ResponseContext.Current property
Example 9-27. Deriving from ResponseClientBase<T>
Example 9-28. Implementing ResponseClientBase<T>
Example 9-29. Implementing ResponseScope<T>
Example 9-30. Queuing up a response as part of the playback transaction
Example 9-31. Responding in a new transaction
Example 9-32. Service-side configuration of the HTTP bridge
Example 9-33. Service-side implementation of the HTTP bridge
Example 9-34. Client-side configuration of the HTTP bridge
Example 9-35. Client-side implementation of the HTTP bridge