Reputation: 2563
If i got a service definition like this:
[PoisonErrorBehavior]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MsgQueue: IMsgQueue
{
public void ProcessMsg(CustomMsg msg)
{
throw new Exception("Test");
}
}
( where ProcessMsg is the registered method for incoming msmq-messages )
and i want to handle the exception with my error handler ( i took the code from msdn as a template for mine ):
public sealed class PoisonErrorBehaviorAttribute : Attribute, IServiceBehavior
{
MsmqPoisonMessageHandler poisonErrorHandler;
public PoisonErrorBehaviorAttribute()
{
this.poisonErrorHandler = new MsmqPoisonMessageHandler();
}
void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
{
}
void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
{
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
channelDispatcher.ErrorHandlers.Add(poisonErrorHandler);
}
}
}
class MsmqPoisonMessageHandler : IErrorHandler
{
public void ProvideFault(Exception error, MessageVersion version, ref System.ServiceModel.Channels.Message fault)
{
}
public bool HandleError(Exception error)
{
string test = error.GetType().ToString();
//
// The type of the exception is never MsmqPoisonMessageException !!!
//
MsmqPoisonMessageException poisonException = error as MsmqPoisonMessageException;
if (null != poisonException)
{
long lookupId = poisonException.MessageLookupId;
Console.WriteLine(" Poisoned message -message look up id = {0}", lookupId);
}
}
then i got the problem that the exception is never of type MsmqPoisonMessageException. I would have expected .NET to magically encapsulate my "new Exception("Test")" in a MsmqPoisonMessageException, but the exception catched in my errorhandler is always of the same type as the exception i threw.
Am i missunderstanding this whole poison message behavior? I thought if an unhandled exception was thrown by my message-handling-code then the exception would turn out to be a MsmqPoisonMessageException, because otherwise i would'nt have a chance to get the lookup-id of msg in the queue.
Thank you all.
Upvotes: 1
Views: 696
Reputation: 43
First of all, you need to be retrieving the messages inside of a transaction, otherwise they won't be put back to the queue when there is an exception thrown from your code. Add this to the ProcessMessage function:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
Also, you need to make sure that binding is set to fault when poison messages are detected, and that the retry count and time are small enough that you'll see it in your testing.
Try these steps (using VS 2008):
(You will probably want different values for ReceiveRetryCount and RetryCycleDelay for your production configuration.)
Upvotes: 1
Reputation: 65411
WCF encapsulates exceptions in a fault exception.
http://msdn.microsoft.com/en-us/library/system.servicemodel.faultexception.aspx
You must also specify which exceptions are to be thrown in the Interface / Contract.
Upvotes: 1