C#Queue Learning Notes: Introduction to MSMQ 2

1. Introduction

According to the Private Queue Interpretation: MachineName\Private$\QueueName is defined as a private queue only for programs that are local to the computer and in some cases for security reasons.So at first it was thought that public queues were the only way to access remote message queues.However, it was later found that public queues depend on Domain Controller. In actual deployment, it is too demanding to require applications using Message Queuing to be in a certain domain.It was later discovered that private queues were also remotely accessible.(Confused why private queues can only be accessed locally, this sentence can be seen everywhere?!)

Local C/S under Workgroup

2.1. Project Establishment

Create 4 new projects:

2.2, Project Code

2.2.1, Model Project

    /// <summary>
    /// Message Queuing Entities
    /// </summary>
    [Serializable]
    public class MqMessage
    {
        /// <summary>
        /// Corresponding Message Of Label
        /// </summary>
        public string Label { get; set; }

        /// <summary>
        /// Corresponding Message Of Body,CommandType Is the type of operation, List<string>Is the list of actions.
        /// </summary>
        public Dictionary<CommandType, List<string>> Body { get; set; } = new Dictionary<CommandType, List<string>>();

        /// <summary>
        /// non-parameter constructor
        /// </summary>
        public MqMessage()
        {
        }

        /// <summary>
        /// Parametric constructor
        /// </summary>
        /// <param name="label"></param>
        /// <param name="body"></param>
        public MqMessage(string label, Dictionary<CommandType, List<string>> body)
        {
            Label = label;
            Body = body;
        }
    }

    /// <summary>
    /// Operation type
    /// </summary>
    public enum CommandType
    {
        Create = 1, //Establish
        Update = 2, //To update
        Delete = 3  //delete
    }
MqMessage.cs

2.2.2, Common Project

    /// <summary>
    /// Log Help Class
    /// </summary>
    public static class LogHelper
    {
        private static readonly string errLogSavePath = ConfigurationManager.AppSettings["ErrLogSavePath"] ?? AppDomain.CurrentDomain.BaseDirectory;

        /// <summary>
        /// Exception Log Method Overload
        /// </summary>
        /// <param name="ex">Exception Information</param>
        public static void WriteLog(Exception ex)
        {
            WriteLog(GetErrMsg(ex));
        }

        /// <summary>
        /// Exception Log Method Overload
        /// </summary>
        /// <param name="message">Log Content</param>
        public static void WriteLog(string message)
        {
            WriteLog(errLogSavePath, message);
        }

        /// <summary>
        /// Exception Log Method Overload
        /// </summary>
        /// <param name="filepath">log file path</param>
        /// <param name="message">Log Content</param>
        public static void WriteLog(string filepath, string message)
        {
            try
            {
                if (!Directory.Exists(filepath))
                {
                    Directory.CreateDirectory(filepath);
                }
                string filename = DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                using (StreamWriter sw = new StreamWriter(filepath + "\\" + filename, true))
                {
                    sw.WriteLine("--------------------------------------------");
                    sw.WriteLine($"{DateTime.Now.ToLongTimeString()}:{DateTime.Now.Millisecond}\t{message}");
                    sw.Close();
                }
            }
            catch (Exception ex)
            {
                throw new Exception(GetErrMsg(ex));
            }
        }

        /// <summary>
        /// Get exception details
        /// </summary>
        /// <param name="ex"></param>
        /// <returns></returns>
        private static string GetErrMsg(Exception ex)
        {
            string errMessage = "";
            for (Exception tempException = ex; tempException != null; tempException = tempException.InnerException)
            {
                errMessage += tempException.Message + Environment.NewLine + Environment.NewLine;
            }
            errMessage += ex.ToString();
            return errMessage;
        }
    }
LogHelper.cs
    /// <summary>
    /// Message Queue Manager
    /// </summary>
    public class MqManager : IDisposable
    {
        private MessageQueue _mq = null;
        private readonly LinkType linkType = LinkType.LocalHost;    //Link type, used remotely LinkType.RemoteServer. 
        private readonly string remoteServer = "192.168.2.165";     //remote server IP address

        public static MqManager LinkServer { get; } = new MqManager();

        /// <summary>
        /// Initialization function
        /// </summary>
        /// <param name="linkType">Link Type</param>
        public void MqManagerInit(LinkType linkType)
        {
            if (_mq == null)
            {
                string _path;
                if (linkType == LinkType.LocalHost)
                {
                    _path = @".\private$\" + (ConfigurationManager.AppSettings["MSMQName"] ?? "HelloWorld");
                }
                else
                {
                    _path = "FormatName:DIRECT=TCP:" + remoteServer + @"\private$\" + (ConfigurationManager.AppSettings["MSMQName"] ?? "HelloWorld");
                }
                _mq = new MessageQueue(_path)
                {
                    Formatter = new BinaryMessageFormatter()
                };
            }
        }

        /// <summary>
        /// Parametric constructor
        /// </summary>
        public MqManager()
        {
            MqManagerInit(linkType);
        }

        /// <summary>
        /// Send Message Queue(affair)
        /// </summary>
        /// <param name="message"></param>
        public void Send(MqMessage message)
        {
            MessageQueueTransaction transaction = new MessageQueueTransaction();
            transaction.Begin();
            _mq.Send(message.Body, message.Label, transaction);
            transaction.Commit();
        }

        /// <summary>
        /// Receive message queue
        /// </summary>
        /// <returns></returns>
        public Message Receive()
        {
            Message msg = null;
            try
            {
                msg = _mq.Receive(new TimeSpan(0, 0, 1));
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

            return msg;
        }

        /// <summary>
        /// Release Resources
        /// </summary>
        public void Dispose()
        {
            if (_mq != null)
            {
                _mq.Close();
                _mq.Dispose();
                _mq = null;
            }
        }
    }

    /// <summary>
    /// Link Type
    /// </summary>
    public enum LinkType
    {
        LocalHost = 1,      //Local Server
        RemoteServer = 2    //remote server
    }
MqManager.cs

2.2.3, Send Project

    class Program
    {
        static void Main(string[] args)
        {
            MqMessage mqMessage = new MqMessage();
            List<string> list = new List<string>();

            Console.WriteLine("Please enter content to send by return, separate multiple content with English commas, exit please enter Exit. ");
            string receiveKey = Console.ReadLine();

            while (receiveKey.ToLower() != "exit")
            {
                if (receiveKey.Length > 0)
                {
                    mqMessage.Label = Guid.NewGuid().ToString();

                    list.Clear();
                    list = receiveKey.Split(new char[] { ',' }).ToList();
                    mqMessage.Body.Clear();
                    mqMessage.Body.Add(CommandType.Create, list);
                    try
                    {
                        MqManager.LinkServer.Send(mqMessage);
                        Console.WriteLine("The content was sent successfully.");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        LogHelper.WriteLog(ex);
                    }
                }
                receiveKey = Console.ReadLine();
            }

            MqManager.LinkServer.Dispose();
        }
    }
Program.cs

2.2.4, Receive Project

    /// <summary>
    /// Receive Message Queue Management(thread)
    /// </summary>
    public class ReceiveManager : IDisposable
    {
        private Thread _thread = null;

        public static ReceiveManager Instance { get; set; } = new ReceiveManager();

        /// <summary>
        /// start
        /// </summary>
        public void Start()
        {
            StartReceive();
        }

        /// <summary>
        /// Receive Threads
        /// </summary>
        private void StartReceive()
        {
            _thread = new Thread(new ThreadStart(Receive))
            {
                Name = "ReceiveThread",
                IsBackground = true
            };
            _thread.Start();
        }

        /// <summary>
        /// Receive Thread Call Method
        /// </summary>
        private void Receive()
        {
            Message msg = null;
            while (true)
            {
                try
                {
                    msg = MqManager.LinkServer.Receive();
                    if (msg != null)
                    {
                        Console.WriteLine("----------------------------------------------------");
                        Console.WriteLine("Lable: " + msg.Label);
                        Dictionary<CommandType, List<string>> keyValuePairs = msg.Body as Dictionary<CommandType, List<string>>;
                        Console.WriteLine("Body CommandType: " + keyValuePairs.Keys.First());
                        Console.WriteLine("Body Details: ");
                        foreach (var item in keyValuePairs.Values.First())
                        {
                            Console.WriteLine(item);
                        }
                        Console.WriteLine("----------------------------------------------------");
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    LogHelper.WriteLog(ex);
                }
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// End
        /// </summary>
        public void Stop()
        {
            Dispose();
        }

        /// <summary>
        /// Release Resources
        /// </summary>
        public void Dispose()
        {
            try
            {
                if (_thread != null)
                {
                    _thread.Abort();
                    _thread.Join();
                    _thread = null;
                }

                MqManager.LinkServer.Dispose();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
ReceiveManage.cs
    class Program
    {
        static void Main(string[] args)
        {
            ReceiveManager.Instance.Start();
            Console.WriteLine("Exit please enter Exit");
            string receiveKey = Console.ReadLine();
            while (receiveKey.ToLower() != "exit")
            {
                receiveKey = Console.ReadLine();
            }
            ReceiveManager.Instance.Stop();
            Console.Read();
        }
    }
Program.cs

2.3. Running tests

Client sends hello,world:

The information received by the server:

3. Remote C/S under Workgroup

3.1, Code Adjustment

Remote C/S under Workgroup, code provided in the example above, will be under Common\MqManager.cs:

private readonly LinkType linkType = LinkType.LocalHost; change to private readonly LinkType linkType = LinkType.RemoteServer; that's it.

3.2. Access rights

Since you are interacting (sending/receiving) queue information with a remote server, the first issue is access rights, no rights, no talk.

The following describes what the remote server (192.168.2.165 in the code, Win7 system) will set up:

3.2.1, Enter compmgmt.msc->Services and Applications->Message Queuing->Right-click Properties->Server Security->Disable Unauthenticated RPC Calls->Check Out->Apply.

3.2.2, Message Queue->Private Queue->Create a new HelloWorld queue used in your code, tick Transactional->OK.

Why build HelloWorld message queues manually?Because you are authorizing anonymous access to this queue, you will see later.As for the transactional tick, this should correspond to the code.Because MessageQueueTransaction is used to send transaction information in this example, this check must be checked. Otherwise, no error message will be sent, but the server will not receive queue information.

3.2.3, Private Queue->HelloWorld->Right-click Properties->Security->ANONYMOUS LOGON->Full Control->Application.

3.2.4, Enter regedit->HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSMQ\Parameters\security->Create two new DWORD values at run time: AllowNonauthenticatedRpc, NewRemoteReadServeryWorkgroupClient->Double-click to change the numeric data to 1.

3.2.5. With regard to firewalls, I have turned off. If your computer firewall is on, please check if Message Queuing is allowed?

3.3. Running tests

Client sends A,B,C,D:

The information received on the server side:

 

Reference from:

    https://www.cnblogs.com/xinhaijulan/archive/2010/08/22/1805768.html

    https://www.cnblogs.com/minily/p/7397746.html

    https://blog.csdn.net/jiyiqinlovexx/article/details/17803857

    https://www.cnblogs.com/mmbbflyer/p/7773303.html

Tags: C# firewall

Posted on Fri, 27 Mar 2020 00:56:26 -0400 by maiza