【问题标题】:Processing MSMQ Message in Windows Service在 Windows 服务中处理 MSMQ 消息
【发布时间】:2012-04-12 07:10:08
【问题描述】:

我有一个用于处理 MSMQ 消息的 Windows 服务。它依赖于以下逻辑

· windows 服务中有一个定时器。每十分钟它会执行一个名为“ProcessMessages”的方法。

· 在这个方法中,它首先通过调用队列的GetAllMessages方法创建一个现有messageIds的列表。

· 对于每个messageId,它接收消息(使用ReceiveById)并将其存储到一个文件中

有没有更好的方法来实现消息处理?

参考:http://www.switchonthecode.com/tutorials/creating-a-simple-windows-service-in-csharp

注意:以下代码在我将其作为服务时没有给出预期的结果;但是事件查看器中没有错误(我没有进行任何显式日志记录)。当它是一个简单的控制台应用程序时,它运行良好。如何纠正它? [现在,当我在下面的 cmets 中将帐户更改为“用户”时,它正在工作]

我的实际要求是在固定的时间段处理所有消息 - 例如仅在上午 10 点和上午 11 点(每天)。做到这一点的最佳方法是什么?

namespace ConsoleSwitchApp
{
    class Program : ServiceBase
    {
        private static Timer scheduleTimer = null;
        static MessageQueue helpRequestQueue = null;
        static System.Messaging.XmlMessageFormatter stringFormatter = null;

        static void Main(string[] args)
        {
            ServiceBase.Run(new Program());
        }

        public Program()
        {
            this.ServiceName = "LijosService6";

            //Queue initialize
            helpRequestQueue = new MessageQueue(@".\Private$\MyPrivateQueue", false);
            stringFormatter = new System.Messaging.XmlMessageFormatter(new string[] { "System.String" });

            //Set Message Filters
            MessagePropertyFilter filter = new MessagePropertyFilter();
            filter.ClearAll();
            filter.Body = true;
            filter.Label = true;
            filter.Priority = true;
            filter.Id = true;
            helpRequestQueue.MessageReadPropertyFilter = filter;

            //Start a timer
            scheduleTimer = new Timer();
            scheduleTimer.Enabled = true;
            scheduleTimer.Interval = 120000;//2 mins
            scheduleTimer.AutoReset = true;
            scheduleTimer.Start();
            scheduleTimer.Elapsed += new ElapsedEventHandler(scheduleTimer_Elapsed);
        }

        protected static void scheduleTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            ProcessMessages();
        }

        private static void ProcessMessages()
        {
            string messageString = "1";

            //Message Processing
            List<string> messageIdList = GetAllMessageId();
            foreach (string messageId in messageIdList)
            {
                System.Messaging.Message messages = helpRequestQueue.ReceiveById(messageId);
                //Store the message into database

                messages.Formatter = stringFormatter;
                string messageBody = System.Convert.ToString(messages.Body);

                if (String.IsNullOrEmpty(messageString))
                {
                    messageString = messageBody;
                }
                else
                {
                    messageString = messageString + "___________" + messageBody;
                }
            }

            //Write File
            string lines = DateTime.Now.ToString();
            lines = lines.Replace("/", "-");
            lines = lines.Replace(":", "_");
            System.IO.StreamWriter file = new System.IO.StreamWriter("c:\\test" + lines + ".txt");
            file.WriteLine(messageString);
            file.Close();
        }

        private static List<string> GetAllMessageId()
        {
            List<string> messageIdList = new List<string>();

            DataTable messageTable = new DataTable();
            messageTable.Columns.Add("Label");
            messageTable.Columns.Add("Body");

            //Get All Messages
            System.Messaging.Message[] messages = helpRequestQueue.GetAllMessages();
            for (int index = 0; index < messages.Length; index++)
            {
                string messageId = (System.Convert.ToString(messages[index].Id));
                messageIdList.Add(messageId);

                messages[index].Formatter = stringFormatter;
                messageTable.Rows.Add(new string[] { messages[index].Label, messages[index].Body.ToString() });
            }

            return messageIdList;
        }


        protected override void OnStart(string[] args)
        {
            base.OnStart(args);
        }

        protected override void OnStop()
        {
            base.OnStop();
        }
    }
}

namespace ConsoleSwitchApp
{
    [RunInstaller(true)]
    public class MyWindowsServiceInstaller : Installer
    {
        public MyWindowsServiceInstaller()
        {
            var processInstaller = new ServiceProcessInstaller();
            var serviceInstaller = new ServiceInstaller();

            //set the privileges
            processInstaller.Account = ServiceAccount.LocalSystem;
            serviceInstaller.DisplayName = "LijosService6";
            serviceInstaller.StartType = ServiceStartMode.Manual;

            //must be the same as what was set in Program's constructor

           serviceInstaller.ServiceName = "LijosService6";

            this.Installers.Add(processInstaller);
            this.Installers.Add(serviceInstaller);
        }
    }
}

【问题讨论】:

  • 可能是权限问题。尝试使用其他内置帐户之一。
  • @M.Babcock 谢谢.. 当我使用 ServiceAccount.User 并提供我的用户名和密码时,服务工作正常。这里建议的帐户是什么?
  • 我强烈建议不要为此在生产环境中使用专用用户帐户。该问题可能与this KB article 有关(与Vista 有关,但在7 和2008 中可能存在相同的问题)。
  • 你的问题中的链接 404s fyi

标签: c# .net wcf windows-services msmq


【解决方案1】:

使用计时器的一个很好的替代方法是使用MessageQueue.BeginReceive 方法并在ReceiveCompleted 事件中工作。这样,您的代码将等待队列中有消息,然后立即处理该消息,然后检查下一条消息。

一个简短的存根(链接的 MSDN 文章中的完整示例。)

private void Start()
{
    MessageQueue myQueue = new MessageQueue(".\\myQueue");

    myQueue.ReceiveCompleted += 
        new ReceiveCompletedEventHandler(MyReceiveCompleted);

    myQueue.BeginReceive();
}

private static void MyReceiveCompleted(Object source, 
    ReceiveCompletedEventArgs asyncResult)
{
    try
    {
        MessageQueue mq = (MessageQueue)source;
        Message m = mq.EndReceive(asyncResult.AsyncResult);

        // TODO: Process the m message here

        // Restart the asynchronous receive operation.
        mq.BeginReceive();
    }
    catch(MessageQueueException)
    {
        // Handle sources of MessageQueueException.
    }

    return; 
}

【讨论】:

  • 使用 Windows 任务计划程序运行控制台应用程序。
【解决方案2】:

为什么不订阅ReceiveCompleted 事件?另一种选择,如果发送者和订阅者都是您正在处理的 .Net 项目,请使用 WCF over MSMQ

【讨论】:

  • 我的要求是在固定的时间段处理所有消息——比如仅在上午 10 点和上午 11 点(每天)。最好的方法是什么?
  • 可能您应该将 MSMQ 访问权限授予匿名域帐户
猜你喜欢
  • 2010-09-27
  • 1970-01-01
  • 2013-10-05
  • 2010-12-04
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
  • 2014-10-22
  • 1970-01-01
相关资源
最近更新 更多