14

I'll start by saying I'm not a .NET developer, but have been thrown into a project where I need to use MSMQ so a classic ASP web application can send messages to a C# Windows Service that handles the processing. I have experience integrating other message queues with other languages, but like I mentioned, I don't have much experience with .NET and Windows development so some guidance would be much appreciated.

Here are my questions...

  1. Could someone provide some basic C# code that listens to an existing MSMQ queue and responds to the new message by doing something simple like writing the current timestamp to a log file or sending an email?

  2. How do I package this code up in Visual Studio .NET to create and install a Windows Service? (What type of project should it be, etc. I'm using Visual C# 2010 Express.)

  3. Finally, I'm not sure which version and/or implementation of MSMQ I need to be using for my requirements with classic ASP. I think the COM version is what I need, but I've also read about a new WCF version, as well as differences between 3.0 and 4.0. Could someone please give me direction on which version I should be using?

Many thanks!

philfeyn
  • 141
  • 1
  • 1
  • 3

2 Answers2

8

You can wait for a message on a given queue using the following code (You want to use the private queue named SomeQueue on your computer, named 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();
        }
    }

Note: the Receove method will block untill a message is received at which point it'll remove the message from the queue and return it.

edit: added code for the implementation of the multithreaded portion (and renamed the above method signature)

Thread Creation Code:

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

I'll just note, that this is untested cod, it's just an quick example

Neowizard
  • 2,981
  • 1
  • 21
  • 39
  • You sure that Exists() call will work? http://blog.plumbersmate.eu/archive/2010/10/18/checking-if-msmq-queues-exist-is-hard-work-so-should.aspx – John Breakwell Oct 18 '10 at 12:35
  • @Neowizard, Using the Windows Service example code above, your code belongs in the OnStart() method of WindowsService1 correct? When a message is received by x.Receive(), where does it get returned? Can you provide some code for an example of your last comment about creating a new thread that waits for messages? For example, when a new message is received? Thanks! – philfeyn Oct 19 '10 at 01:48
  • The code above is just a basic code for setting a thread to wait for a message to arrive in the queue. It does not take into effect problems resulting from services or anything other then the MSMQ. I'll add some code to the answer to improve on it, but it'll be a better idea for you to do some sandbox playing with the MessageQueue class\object – Neowizard Oct 19 '10 at 07:13
  • "it should not be accessible from a remote location (hence "private")." Huh? Private queues are private only in that they are not published to Active Directory. Just like a telephone book - my phone number may not be in the book but it doesn't stop anyone phoning me. Exists() doesn't work on remote queues because the MSMQ dev team didn't provide a way for it to work. Just like you can't create remote private queues. – John Breakwell Jan 28 '11 at 02:37
  • 1
    @JohnBreakwell, You're right. I don't know what I was thinking when I wrote that comment. Must have been a very bad day. It's removed to avoid confusion. – Neowizard Jun 14 '14 at 07:05
4

As far as I know, Visual Studio Express does not have a project template for a service. That does not mean you cannot write a windows service with VSE, just that you will not have a template to get you started.

To create a service you can just create a normal Console application. Create the service class which will be responsible for the actual service implementation. It will look something like this

using System.ServiceProcess;

namespace WindowsService1
{
  public partial class Service1 : ServiceBase
  {
    public Service1()
    {
      InitializeComponent();
    }

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

    protected override void OnStop()
    {
    }
  }
}

Then the Service startup code can go into the Main function of your service.

using System.ServiceProcess;

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

That should give you the basic framework for your service. The other thing you will need is to add an installer for the service so that it can be installed as a service. The following should get you started, note I have note tested this.

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

Given the above, you should have enough to search around or ask for more details around the service creation. As for the MSMQ listener, you can use the following MSDN article as a starting point

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

Chris Taylor
  • 52,623
  • 10
  • 78
  • 89
  • great sample code to get me started on the Windows Service, thanks. – philfeyn Oct 18 '10 at 04:28
  • are there other ways to install the service, even if its a manual install? Having to hard-code the username and password to run the service as into the code seems bad practice to me. – philfeyn Oct 19 '10 at 02:23
  • @philfeyn, you can set the ServiceProcessInstaller.Account to select the type of account. If it is set to ServiceAccount.User and the username/password are set to null, you will be prompted for the credentials when you install the service. You can manually install the service using InstallUtil.exe which comes with the .NET framework. – Chris Taylor Oct 19 '10 at 03:21
  • As of March 2019, there is this tutorial on service creation, which largely aligns with this answer: https://learn.microsoft.com/en-us/dotnet/framework/windows-services/walkthrough-creating-a-windows-service-application-in-the-component-designer – Intrastellar Explorer Oct 28 '19 at 18:43