如果我得到这样的服务定义:
[PoisonErrorBehavior]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class MsgQueue: IMsgQueue
{
public void ProcessMsg(CustomMsg msg)
{
throw new Exception("Test");
}
}
(其中ProcessMsg是传入的msmq消息的注册方法)
我想用我的错误处理程序处理异常(我把msdn的代码作为我的模板):
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);
}
}
然后我遇到的问题是异常永远不会是MsmqPoisonMessageException类型。我原以为.NET会在MsmqPoisonMessageException中神奇地封装我的“新异常(”Test“)”,但是我的错误处理程序中捕获的异常总是和我抛出的异常类型相同。
我是否想知道这整个毒药信息的行为?我想如果我的消息处理代码抛出了未处理的异常,那么异常将变成MsmqPoisonMessageException,因为否则我将无法获得队列中msg的lookup-id。
谢谢大家。
答案 0 :(得分:1)
WCF在异常中封装异常。
http://msdn.microsoft.com/en-us/library/system.servicemodel.faultexception.aspx
您还必须指定在接口/合同中抛出哪些异常。
答案 1 :(得分:1)
首先,您需要检索事务内部的消息,否则当代码中抛出异常时,它们将不会被放回队列。将其添加到ProcessMessage函数:
[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
此外,您需要确保在检测到有害消息时将绑定设置为错误,并且重试次数和时间足够小,以便您在测试中看到它。
尝试以下步骤(使用VS 2008):
(对于您的生产配置,您可能需要不同的ReceiveRetryCount和RetryCycleDelay值。)