Click here to Skip to main content
15,892,809 members
Articles / Programming Languages / XML

NullTransport for WCF

Rate me:
Please Sign up or sign in to vote.
4.91/5 (48 votes)
1 Oct 200712 min read 189.7K   1.7K   121  
This article describes design, implementation and the usage of the custom in-process transport for Microsoft Windows Communication Foundation (WCF) model.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Xml;
using System.Transactions;
using System.ServiceModel;
using System.ServiceModel.MsmqIntegration;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Net.Security;

using RKiss.NullChannelLib;

namespace Host4
{
    #region Contract
    [ServiceContract(SessionMode=SessionMode.Required)]
    //[ServiceContract]
    public interface ITest
    {
        //[OperationContract(IsOneWay = true, IsInitiating=true)]
        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Allowed)]
        void Ping(int value);

        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Allowed)]
        string Ping2(int value);
    }

    [ServiceContract]
    [ServiceKnownType(typeof(string))]
    public interface ITestQueue
    {
        [OperationContract(IsOneWay = true, Action = "*")]
        [TransactionFlow(TransactionFlowOption.Allowed)]
        void Show(MsmqMessage<string> msg);
    }
    #endregion

    #region Service
    [ServiceBehavior(IncludeExceptionDetailInFaults = true, ConcurrencyMode = ConcurrencyMode.Single)]
    public class Test : ITest
    {
        const string strQueueName = @".\private$\test";

        [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=true)]
        public void Ping(int value)
        {
            //Thread.Sleep(4000);
            TransactionStatus txstatus = TransactionStatus.InDoubt;
            if (Transaction.Current != null)
                txstatus = Transaction.Current.TransactionInformation.Status;

            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine("\n[tid={0}, tx={1}]  *** PING Service: {2} ***\n", Thread.CurrentThread.GetHashCode(), txstatus, value);
            Console.ResetColor();

            //Thread.Sleep(5000);

            // for test purpose we are using MSMQ resource manager
            System.Messaging.MessageQueue mq = new System.Messaging.MessageQueue(strQueueName);
            mq.Send("This is a test message", value.ToString(), System.Messaging.MessageQueueTransactionType.Automatic);

            //if(state == 2)
            //throw new Exception("M A N U A L L Y  A B O R T E D");
        }

        [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
        public string Ping2(int value)
        {
            TransactionStatus txstatus = TransactionStatus.InDoubt;
            if (Transaction.Current != null)
                txstatus = Transaction.Current.TransactionInformation.Status;

            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine("\n[tid={0}, tx={1}]  *** PING_2 Service: {2} ***\n", Thread.CurrentThread.GetHashCode(), txstatus, value);
            Console.ResetColor();

            string retval = string.Format("[{0}, {1}, Hello from tid={2}]", DateTime.Now.ToShortTimeString(), value, Thread.CurrentThread.GetHashCode());          

            //using (DependentTransaction dtx = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete))
            {
                // for test purpose we are using MSMQ resource manager
                System.Messaging.MessageQueue mq = new System.Messaging.MessageQueue(strQueueName);
                mq.Send(retval, value.ToString(), System.Messaging.MessageQueueTransactionType.Automatic);

                //throw new Exception("M A N U A L L Y  A B O R T E D");
                //dtx.Complete();
            }

            //Thread.Sleep(62000);

            return retval;
        }
    }

    [ServiceBehavior(IncludeExceptionDetailInFaults = true, ConcurrencyMode = ConcurrencyMode.Single)]
    public class TestQueue : ITestQueue
    {
        [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
        public void Show(MsmqMessage<string> msg)
        {
            Console.ForegroundColor = ConsoleColor.Cyan;
            Console.WriteLine("\n*** Queue: Label[{0}], Body[{1}] ***\n", msg.Label, msg.Body);
            Console.ResetColor();
        }
    }
    #endregion


    #region tester
    class Program4
    {
        const string strQueueName = @".\private$\test";
  
        [MTAThread]
        static void Main(string[] args)
        {
            //
            ServiceHost host = null;
            ServiceHost host2 = null;
            try
            {
                // Check and Create the transacted MSMQ queue 
                if (!System.Messaging.MessageQueue.Exists(strQueueName))
                {
                    Console.WriteLine("\nCreating a transactional private queue 'test'  +++\n");
                    System.Messaging.MessageQueue.Create(strQueueName, true);
                }

                using (host = new ServiceHost(typeof(Test)))
                using (host2 = new ServiceHost(typeof(TestQueue)))
                {
                    host.Open();
                    host2.Open();

                    Thread.Sleep(2000);
                    Console.WriteLine("\npress any key to continue ...\n");
                    Console.ReadLine();

                    double totalTime = 0;
                    for (int ii = 0; ii < 1000; ii++)
                    {
                        // timestamp
                        DateTime startDT = DateTime.Now; 

                        // action
                        worker(ii, "gaga");

                        // done
                        double delta = (DateTime.Now - startDT).TotalMilliseconds;
                        totalTime += delta;

                        Console.WriteLine("\n[{0}, {1:###.###}ms] +++ press any key to continue +++\n", ii, (DateTime.Now - startDT).TotalMilliseconds);
                        Console.ReadLine(); 
                    }

                    Console.WriteLine("\n[~time = {0:###.###}ms] +++ press any key to close a ServiceHost +++\n", totalTime / 1000);
                    Console.ReadLine();
                    host.Close();
                    host2.Close();
                }
            }
            catch (CommunicationException ex)
            {
                if (host != null)
                    host.Abort();
                if (host2 != null)
                    host2.Abort();

                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("\n" + ex.Message);
                Console.ResetColor();
                Console.ReadLine();
            }
            catch (Exception ex)
            {
                if (host != null)
                    host.Abort();
                if (host2 != null)
                    host2.Abort();

                Console.WriteLine("\n" + ex);
                Console.ReadLine();
            }
            finally
            {
                Console.WriteLine("\n*** press any key to exit ... ***\n");
                Console.ReadLine();
            }

        }

        internal static void worker(int loop, string name)
        {
            //ThreadPool.QueueUserWorkItem(delegate
            //{
                ChannelFactory<ITest> factory = null;
                try
                {
                    factory = new ChannelFactory<ITest>(name);
                    ITest channel = factory.CreateChannel();

                    using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required))
                    {
                        string response = string.Empty;
                        response = channel.Ping2(loop);
                        //channel.Ping(loop);
                       
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine(string.Format("[{0}, {1}]: {2}, tid={3}\n", loop, name, response, Thread.CurrentThread.GetHashCode()));
                        Console.ResetColor();

                        //Thread.Sleep(1000);

                        Console.WriteLine("\n+++ Press 'a' to abort or any key to finish a transaction. Timeout = 60sec. +++\n");

                        ConsoleKeyInfo ki = Console.ReadKey();
                        if (ki.Key == ConsoleKey.A)
                        {
                            throw new Exception("M A N U A L Y  A B O R T E D");
                        }
                                 
                        ts.Complete();
                    }
                    ((IChannel)channel).Close();
                    factory.Close();
                }
                catch (Exception ex)
                {
                    if (factory != null) factory.Abort();

                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("\n" + ex.Message);
                    Console.ResetColor();
                }

            //});
        }
  
    }
    #endregion

}


By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions