【问题标题】:How to Create a C# Listener Service for MSMQ as a Windows Service如何为 MSMQ 创建 C# 侦听器服务作为 Windows 服务
【发布时间】:2011-04-26 18:26:30
【问题描述】:

我首先要说我不是 .NET 开发人员,但我被投入到一个需要使用 MSMQ 的项目中,以便经典的 ASP Web 应用程序可以将消息发送到处理处理的 C# Windows 服务。我有将其他消息队列与其他语言集成的经验,但正如我所提到的,我在 .NET 和 Windows 开发方面没有太多经验,因此非常感谢一些指导。

这是我的问题...

  1. 有人可以提供一些基本的 C# 代码来侦听现有的 MSMQ 队列并通过执行一些简单的操作(例如将当前时间戳写入日志文件或发送电子邮件)来响应新消息?

    李>
  2. 如何在 Visual Studio .NET 中打包此代码以创建和安装 Windows 服务? (应该是什么类型的项目等等,我用的是Visual C# 2010 Express。)

  3. 最后,我不确定我需要使用哪个版本和/或实现的 MSMQ 来满足我对经典 ASP 的要求。我认为 COM 版本是我所需要的,但我也阅读了新的 WCF 版本,以及 3.0 和 4.0 之间的差异。有人可以指导我应该使用哪个版本吗?

非常感谢!

【问题讨论】:

    标签: c# windows-services asp-classic msmq


    【解决方案1】:

    您可以使用以下代码在给定队列上等待消息(您想在您的计算机上使用名为 SomeQueue 的私有队列,命名为 ComputerName => QueueName = @"ComputerName\private$\SomeQueue")

        public void AsyncWatchQueue(object encapsulatedQueueName)
        {
            Message newMessage;
            MessageQueue queue;
    
            string queueName = encapsulatedQueueName as string;
            if (queueName == null)
                return;
    
            try
            {
                if (!MessageQueue.Exists(queueName))
                    MessageQueue.Create(queueName);
                else
                {
                    queue = new MessageQueue(queueName);
    
                    if (queue.CanRead)
                        newMessage = queue.Receive();
                }
                HandleNewMessage(newMessage); // Do something with the message
            }
            // This exception is raised when the Abort method 
            // (in the thread's instance) is called
            catch (ThreadAbortException e) 
            {
                //Do thread shutdown
            }
            finally
            {
                queue.Dispose();
            }
        }
    

    注意:Receove 方法会一直阻塞,直到收到一条消息,此时它会从队列中删除该消息并返回。

    编辑:为多线程部分的实现添加了代码(并重命名了上述方法签名)

    线程创建代码:

            public Thread AddWatchingThread(string QueueName)
        {
            Thread Watcher = 
                new Thread(new ParameterizedThreadStart(AsyncWatchQueue));
            Watcher.Start(QueueName);
            // The thread instance is used to manipulate (or shutdown the thread)
            return Watcher; 
        }
    

    请注意,这是未经测试的鳕鱼,只是一个简单的示例

    【讨论】:

    • 您确定 Exists() 调用会起作用吗? blog.plumbersmate.eu/archive/2010/10/18/…
    • @Neowizard,使用上面的 Windows 服务示例代码,您的代码属于 WindowsService1 的 OnStart() 方法对吗?当 x.Receive() 收到一条消息时,它在哪里返回?您能否提供一些代码作为您上一条关于创建等待消息的新线程的评论的示例?例如,当收到一条新消息时?谢谢!
    • 上面的代码只是设置线程等待消息到达队列的基本代码。它不会影响由服务或除 MSMQ 之外的任何其他东西引起的问题。我将在答案中添加一些代码以对其进行改进,但您最好使用 MessageQueue 类\object 做一些沙盒游戏
    • “它不应该从远程位置访问(因此是“私有”)。”嗯?专用队列是专用的,只是因为它们不发布到 Active Directory。就像电话簿一样——我的电话号码可能不在电话簿上,但它不会阻止任何人给我打电话。 Exists() 不适用于远程队列,因为 MSMQ 开发团队没有为其提供工作方式。就像你不能创建远程私有队列一样。
    • @JohnBreakwell,你是对的。我不知道我在写这篇评论时在想什么。一定是非常糟糕的一天。为避免混淆,已将其删除。
    【解决方案2】:

    据我所知,Visual Studio Express 没有用于服务的项目模板。这并不意味着您不能使用 VSE 编写 Windows 服务,只是您没有模板可以帮助您入门。

    要创建服务,您只需创建一个普通的控制台应用程序。创建负责实际服务实现的服务类。它看起来像这样

    using System.ServiceProcess;
    
    namespace WindowsService1
    {
      public partial class Service1 : ServiceBase
      {
        public Service1()
        {
          InitializeComponent();
        }
    
        protected override void OnStart(string[] args)
        {
        }
    
        protected override void OnStop()
        {
        }
      }
    }
    

    然后Service启动代码就可以进入到你的服务的Main函数中了。

    using System.ServiceProcess;
    
    namespace WindowsService1
    {
      static class Program
      {
        static void Main()
        {
          ServiceBase[] ServicesToRun;
          ServicesToRun = new ServiceBase[] 
                { 
                    new Service1() 
                };
          ServiceBase.Run(ServicesToRun);
        }
      }
    }
    

    这应该为您提供服务的基本框架。您需要的另一件事是为该服务添加一个安装程序,以便它可以作为服务安装。以下内容应该可以帮助您入门,请注意我已经对此进行了测试。

    using System.ComponentModel;
    using System.Configuration.Install;
    using System.ServiceProcess;
    
    namespace WindowsService1
    {
      [RunInstaller(true)]
      public class ProjectInstaller : Installer
      {
        private ServiceProcessInstaller serviceProcessInstaller1;
        private ServiceInstaller serviceInstaller1;
    
        public ProjectInstaller()
        {
          this.serviceProcessInstaller1 = new ServiceProcessInstaller();
          this.serviceInstaller1 = new ServiceInstaller();
    
          this.serviceProcessInstaller1.Password = null;
          this.serviceProcessInstaller1.Username = null;
    
          this.serviceInstaller1.ServiceName = "Service1";
    
          this.Installers.AddRange(new System.Configuration.Install.Installer[] {
            this.serviceProcessInstaller1,
            this.serviceInstaller1});
        }
      }
    }
    

    鉴于上述情况,您应该有足够的时间搜索或询问有关服务创建的更多详细信息。至于MSMQ监听器,可以参考以下MSDN文章入手

    http://msdn.microsoft.com/en-us/library/ms978425.aspx

    【讨论】:

    • 很好的示例代码让我开始使用 Windows 服务,谢谢。
    • 是否有其他方法可以安装该服务,即使它是手动安装?必须硬编码用户名和密码才能在代码中运行服务对我来说似乎是一种不好的做法。
    • @philfeyn,您可以设置 ServiceProcessInstaller.Account 以选择帐户类型。如果设置为 ServiceAccount.User 并且用户名/密码设置为 null,则在安装服务时将提示您输入凭据。您可以使用 .NET 框架附带的 InstallUtil.exe 手动安装该服务。
    • 截至 2019 年 3 月,有这个关于服务创建的教程,与这个答案基本一致:docs.microsoft.com/en-us/dotnet/framework/windows-services/…
    猜你喜欢
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 2015-10-06
    • 2014-03-16
    • 1970-01-01
    • 1970-01-01
    • 2016-12-30
    相关资源
    最近更新 更多