我理解MsmqPoisonMessageException错了吗?

时间:2009-06-19 10:10:04

标签: wcf exception msmq

如果我得到这样的服务定义:

[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。

谢谢大家。

2 个答案:

答案 0 :(得分:1)

WCF在异常中封装异常。

http://msdn.microsoft.com/en-us/library/system.servicemodel.faultexception.aspx

您还必须指定在接口/合同中抛出哪些异常。

答案 1 :(得分:1)

首先,您需要检索事务内部的消息,否则当代码中抛出异常时,它们将不会被放回队列。将其添加到ProcessMessage函数:

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]

此外,您需要确保在检测到有害消息时将绑定设置为错误,并且重试次数和时间足够小,以便您在测试中看到它。

尝试以下步骤(使用VS 2008):

  1. 打开app.config文件的WCF配置工具
  2. 在树中选择Bindings,然后单击任务区域中的“New Binding Configuration”
  3. 选择端点的绑定类型(可能是netMsmqBinding或msmqIntegrationBinding)
  4. 设置新绑定配置的名称
  5. 将ReceiveErrorHandling属性设置为“Fault”
  6. 将ReceiveRetryCount属性设置为2
  7. 将RetryCycleDelay设置为“00:00:10”
  8. 选择服务的端点,并将绑定配置设置为您在步骤4中指定的名称。
  9. (对于您的生产配置,您可能需要不同的ReceiveRetryCount和RetryCycleDelay值。)