Wednesday, July 20, 2011

MsmqException (0xC00E0051) 60 seconds after a WCF Service is executed

I know that this is the type of posts that only few people will find interesting.
But so many times I googled about some weird exception message, found that another developer wrote about it and saved me hours of work, that now, after spending several days trying to solve this issue, I feel an obligation to post about it.


Symptoms


When using NetMsmqBinding with a transactional queue and a Service is exposed with more than one Endpoint (two o more svc files with the same service type defined in the markup), a MsmqException is sometimes thrown just 60 seconds after the message is processed.

MyService1.svc
<%@ServiceHost language="c#" Debug="true" Service="Service" %>

MyService2.svc
<%@ServiceHost language="c#" Debug="true" Service="Service" %>

Web.config
<service name="Service">
  <endpoint contract="IService1" binding="netMsmqBinding" 
    address="net.msmq://localhost/private/MsmqService/Service1.svc" />
  <endpoint contract="IService2" binding="netMsmqBinding" 
    address="net.msmq://localhost/private/MsmqService/Service2.svc" />
</service>

Code
public class Service : IService1, IService2 {...}

Exception
System.ServiceModel.MsmqException (0xC00E0051): An error occurred while receiving a message from the queue: Unrecognized error -1072824239 (0xc00e0051). Ensure that MSMQ is installed and running. Make sure the queue is available to receive from. at System.ServiceModel.Channels.MsmqInputChannelBase.TryReceive(TimeSpan timeout, Message& message) at System.ServiceModel.Dispatcher.InputChannelBinder.TryReceive(TimeSpan timeout, RequestContext& requestContext) at System.ServiceModel.Dispatcher.ErrorHandlingReceiver.TryReceive(TimeSpan timeout, RequestContext& requestContext)

Note: You won't see the exception unless you enable the WCF Trace (system.diagnostics) or add an IErrorHandler.


Cause


This issue occurs because the SMSvcHost.exe is activating two ServiceHost instances using the *same* endpoint when a new message arrives.


While the first instance receives and process the message, committing the corresponding COM+ transaction, the second instance creates another COM+ transaction and waits for another incoming message.

After 60 seconds, the second transaction is aborted (COM+ timeout error 0xC00E0051) and the exception is thrown.


Resolution


Instead of creating one Service with two Endpoints, you need to create two separate Services with just one Endpoint each of them.

MyService1.svc
<%@ServiceHost language="c#" Debug="true" Service="Service1"%>

MyService2.svc
<%@ServiceHost language="c#" Debug="true" Service="Service2"%>

Web.config
<service name="Service1">
  <endpoint contract="IService1" binding="netMsmqBinding" 
    address="net.msmq://localhost/private/MsmqService/Service1.svc" />
</service>
<service name="Service2">
  <endpoint contract="IService2" binding="netMsmqBinding" 
    address="net.msmq://localhost/private/MsmqService/Service2.svc" />
</service>

Code
public class Service1 : IService1 {...}
public class Service2 : IService2 {...}

After doing that, only one instance of the ServiceHost is created, so the COM+ timeout exception is not thrown anymore.

I have created a bug in connect.microsoft.com: http://connect.microsoft.com/wcf/feedback/details/680020/msmqexception-0xc00e0051-60-seconds-after-a-wcf-service-is-executed


Additional Information


When the exception is thrown, sometimes the ServiceHost faults and the SMSvcHost.exe process doesn't call it again.

The following fix seems to solve this issue: 2504602 (download).

Another way to solve this is to attach a handler to the ServiceHost.Faulted event and re-create the ServiceHost every time this happens (for more details see this link).


No comments: