如何将MSMQ的C#侦听器服务创建为Windows服务

如何将MSMQ的C#侦听器服务创建为Windows服务,c#,windows-services,asp-classic,msmq,C#,Windows Services,Asp Classic,Msmq,首先我要说的是,我不是.NET开发人员,但我参与了一个需要使用MSMQ的项目,这样一个经典的ASP web应用程序就可以将消息发送到处理该处理的C#Windows服务。我有将其他消息队列与其他语言集成的经验,但正如我提到的,我在.NET和Windows开发方面没有太多经验,因此希望能提供一些指导 以下是我的问题 有人能提供一些基本的C#代码来侦听现有的MSMQ队列并通过简单的操作(如将当前时间戳写入日志文件或发送电子邮件)来响应新消息吗 如何在Visual Studio.NET中打包此代码以创建

首先我要说的是,我不是.NET开发人员,但我参与了一个需要使用MSMQ的项目,这样一个经典的ASP web应用程序就可以将消息发送到处理该处理的C#Windows服务。我有将其他消息队列与其他语言集成的经验,但正如我提到的,我在.NET和Windows开发方面没有太多经验,因此希望能提供一些指导

以下是我的问题

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

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

  • 最后,我不确定我需要使用哪个版本和/或MSMQ实现来满足我对经典ASP的需求。我认为COM版本正是我所需要的,但我也读到了一个新的WCF版本,以及3.0和4.0之间的差异。有人能告诉我应该使用哪个版本吗


  • 非常感谢

    据我所知,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()
        {
        }
      }
    }
    
    然后服务启动代码可以进入服务的
    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文章作为起点


    您可以使用以下代码在给定队列上等待消息(您希望使用计算机上名为SomeQueue的专用队列,名为ComputerName=>QueueName=@“ComputerName\private$\SomeQueue”)

    注意:receve方法将阻塞,直到收到消息,此时它将从队列中删除并返回消息

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

    线程创建代码:

            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; 
        }
    

    我要注意的是,这是一个未经测试的cod,它只是一个快速示例

    很好的示例代码,可以让我开始使用Windows服务,谢谢。即使是手动安装,还有其他方法可以安装该服务吗?在我看来,必须硬编码用户名和密码才能在代码中运行服务是一种糟糕的做法。@philfeyn,您可以设置ServiceProcessInstaller.Account来选择帐户类型。如果设置为ServiceAccount.User且用户名/密码设置为null,则安装服务时将提示您输入凭据。您可以使用.NET framework附带的InstallUtil.exe手动安装该服务。从2019年3月起,本教程介绍了服务创建,这与以下答案基本一致:您确定Exists()调用可以工作吗@Neowizard,使用上面的Windows服务示例代码,您的代码属于WindowsService1的OnStart()方法,对吗?当x.Receive()接收到消息时,它从何处返回?您能否提供一些代码作为您上次关于创建等待消息的新线程的评论的示例?例如,当收到新消息时?谢谢上面的代码只是设置线程等待消息到达队列的基本代码。它不考虑由服务或MSMQ以外的任何内容导致的问题。我将在答案中添加一些代码来改进它,但是您最好使用MessageQueue类\对象进行一些沙箱游戏“它不应该从远程位置访问(因此为“私有”)。”嗯?专用队列只有在未发布到Active Directory时才是专用的。就像电话簿一样——我的电话号码可能不在电话簿中,但这不会阻止任何人给我打电话。Exists()在远程队列上不起作用,因为MSMQ开发团队没有为它提供工作方式。就像你不能创建远程私有队列一样。@JohnBreakwell,你说得对。我不知道我写那篇评论时在想什么。今天一定很糟糕。它被删除以避免混淆。
            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; 
        }