views:

69

answers:

2

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!

A: 

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
@Chris, great sample code to get me started on the Windows Service, thanks.
philfeyn
@Chris, 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
@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
A: 

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
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
@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
@John, good point. In my case, messages will be sent and received all on the same server, so the issue with remote servers don't come into play. However, it would be nice to see some example code of handling a message that does not get received.
philfeyn
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
@John the Exist method **must** fail on a call to a remote private queue, as it should not be accessible from a remote location (hance "private"). I hope that clears that point
Neowizard