Sunday, February 27, 2011

WCF/MSMQ/.Net 4.0 stops processing messages–code fix

I recently upgraded a self hosted WCF service to .Net 4.0. Everything seemed to go well, but a few hours after deploying the service messages started piling up in the queue. I check the service host process and it was idle. It was still executing, but the service had stopped pulling messages. After a bit of trial and error I have discovered the problem and hopefully a solution.

The problem

It seems that .Net 4 has changed the behavior of WCF/MSMQ services slightly. If a problem occurs with the queue, the service host faults and stops.

The solution (I think)

Here is the code I came up with to address the problem. I wrote a class that creates the ServiceHost and attaches an event handlers to the Faulted event. If a fault occurs, I abort the ServiceHost and restart a new instance. (This is for a self-hosted WCF service – if you are hosting your service in IIS/WAS, I think you need to create a ServiceHostFactory class.)  Here is my code:

    /// <summary>
/// In .Net 4, the WCF/MSMQ behavior seems to have changed slightly. Occasionally, the service will fault and not restart causing
/// messages to get stuck in the queue. This class attempts to abort and re-start the service host in the event of a fault.
/// </summary>
/// <typeparam name="T">Your service class</typeparam>
public class RestartingServiceHost<T>
{
protected static readonly log4net.ILog Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
ServiceHost _serviceHost;

public void Start()
{
_serviceHost = new ServiceHost(typeof(T));
_serviceHost.Faulted += new EventHandler(host_Faulted);
_serviceHost.Open();
}

private void Restart()
{
_serviceHost.Abort();
Start();
}

private void host_Faulted(object sender, EventArgs e)
{
Log.Info("Host faulted. Restarting service.");
Restart();
}
}


To use the class, simply create an instance of this class using the type of your service class:



var host = new RestartingServiceHost<MyService>();
host.Start();



That’s it. It seems to be working so far.

No comments: