DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

WCF MSMQ Factory Class

06.02.2010
| 2033 views |
  • submit to reddit
        
/// <summary>
    /// WCF MSMQ Factory class, waarmee zowel server als client programmatisch aangemaakt kunnen worden.
    /// Gebaseerd op een idee van Geoffrey Vandiest 
    /// (http://geoffrey.vandiest.biz/post/Create-a-WCF-service-and-client-using-Msmq-programmatically.aspx).
    /// Zie ook http://www.devx.com/enterprise/Article/39015/1954 voor een overzicht van de architectuur.
    /// 
    /// </summary>
    /// <typeparam name="I">ServiceInterface</typeparam>
    public class WCFMessagingQueueFactory<I>
    {
        private string _netmsmqAddress;
        private string _netmsmqDLQAddress;
        private TimeSpan _timeToLive = new TimeSpan(24, 0, 0);
        private bool _inActiveDirectory = false;

        /// <summary>
        /// Specificeert of deze queue vanuit een machine in een activedirectory benaderd wordt,
        /// of via een machine die alleen aan een workgroup verbonden is.
        /// Standaard waarde = false.
        /// Zie:
        /// http://msdn.microsoft.com/en-us/library/system.servicemodel.configuration.netmsmqbindingelement.useactivedirectory.aspx
        /// http://msdn.microsoft.com/en-us/library/ms585430.aspx
        /// http://msdn.microsoft.com/en-us/library/system.servicemodel.netmsmqsecuritymode.aspx
        /// </summary>
        /// <value><c>true</c> if [in active directory]; otherwise, <c>false</c>.</value>
        public bool InActiveDirectory
        {
            get { return _inActiveDirectory; }
            set { _inActiveDirectory = value; }
        }

        /// <summary>
        /// TimeToLive bepaalt hoe lang een bericht in de queue blijft na verzenden. Nadat
        /// TimeToLive verstreken is wordt het bericht in de custom deadletter queue geplaatst.
        /// </summary>
        /// <value>The time to live.</value>
        public TimeSpan TimeToLive
        {
            get { return _timeToLive; }
            set { _timeToLive = value; }
        }

        /// <summary>
        /// Constructor van <see cref="WCFMessagingQueueFactory<I>"/> class.
        /// </summary>
        /// <param name="queueName">Naam van de queue.</param>
        [MessageQueuePermission(SecurityAction.Demand, Unrestricted=true)]
        public WCFMessagingQueueFactory(string queueName)
        {
            string _msmqAddress = String.Format(@".\private$\{0}", queueName);
            _netmsmqAddress = String.Format(@"net.msmq://localhost/private/{0}", queueName);
            string _msmqDLQAddress = String.Format(@"{0}DLQ", _msmqAddress);
            _netmsmqDLQAddress = String.Format(@"{0}DLQ", _netmsmqAddress);

            if (!MessageQueue.Exists(_msmqAddress))
                MessageQueue.Create(_msmqAddress, true);

            if (!MessageQueue.Exists(_msmqDLQAddress))
                MessageQueue.Create(_msmqDLQAddress, true);
        }

        /// <summary>
        /// Maakt een server aan.
        /// </summary>
        /// <param name="namespaceName">Naam van de namespace.</param>
        /// <returns></returns>
        public ServiceHost CreateServer<T>(string namespaceName)
        {
            var sHost = new ServiceHost(typeof(T));
            NetMsmqBinding binding = null;
            if (InActiveDirectory)
            {
                binding = new NetMsmqBinding(NetMsmqSecurityMode.Transport);
            }
            else
            {
                binding = new NetMsmqBinding(NetMsmqSecurityMode.None);
            }

            // Hier worden de binding variabelen ingesteld die van belang zijn voor de server
            // zie http://msdn.microsoft.com/en-us/library/system.servicemodel.configuration.netmsmqbindingelement_members.aspx
            
            // probeer maximaal 5 keer het bericht uit de queue op te halen
            binding.ReceiveRetryCount = 1;
            // maximaal aantal pogingen om bericht uit de queue op te halen.
            //  (1 + MaxRetryCycles) * (ReceiveRetryCount + 1) = totaal aantal pogingen.
            binding.MaxRetryCycles = 3;
            // als het ophalen na 5 seconden niet gelukt is, timeout exceptie
            binding.ReceiveTimeout = new TimeSpan(0, 0, 5);
            // als het ophalen niet lukt, stuur het bericht dan door naar de custom deadletter queue
            binding.ReceiveErrorHandling = ReceiveErrorHandling.Reject;
            // deze queue is niet volatile (alleen in geheugen), bij stroomstoring is het bericht er nog
            binding.Durable = true;
            // toegestane tijdspanne voor openen verbinding
            binding.OpenTimeout = new TimeSpan(0, 0, 5);
            // toegestane tijdspanne voor sluiten verbinding
            binding.CloseTimeout = new TimeSpan(0, 0, 5);

            binding.Namespace = namespaceName;
            ServiceEndpoint serviceEndPoint = sHost.AddServiceEndpoint(typeof(I),
               binding,
               new Uri(_netmsmqAddress)
            );

            return sHost;
        }

        /// <summary>
        /// Maakt een client.
        /// </summary>
        /// <param name="namespaceName">Name van de namespace.</param>
        /// <returns></returns>
        public ChannelFactory<I> CreateClient(string namespaceName)
        {
            var binding = new NetMsmqBinding(NetMsmqSecurityMode.None);

            // Hier worden de binding variabelen ingesteld die van belang zijn voor de client
            // zie http://msdn.microsoft.com/en-us/library/system.servicemodel.configuration.netmsmqbindingelement_members.aspx
            
            // levensduur bericht
            binding.TimeToLive = TimeToLive;
            // er wordt maximaal 1 keer een bericht aangeboden, bij fouten direct door naar deadletter queue
            binding.ExactlyOnce = true;
            // deze queue is niet volatile (alleen in geheugen), bij stroomstoring is het bericht er nog
            binding.Durable = true;
            // er wordt een eigen deadletter queue aangeboden
            binding.DeadLetterQueue = DeadLetterQueue.Custom;
            // het adres van de eigen deadletter queue
            binding.CustomDeadLetterQueue = new Uri(_netmsmqDLQAddress);
            // de namespace
            binding.Namespace = namespaceName;
            // gebruik geen active directory om de naam van de queue om te zetten.
            binding.UseActiveDirectory = InActiveDirectory;
            // toegestane tijdspanne voor openen verbinding
            binding.OpenTimeout = new TimeSpan(0, 0, 5);
            // toegestane tijdspanne voor sluiten verbinding
            binding.CloseTimeout = new TimeSpan(0, 0, 5);

            var address = new EndpointAddress(String.Format(_netmsmqAddress));

            var channelFactory = new ChannelFactory<I>(binding, address);

            return channelFactory;
        }
    }