Я неправильно понял MsmqPoisonMessageException?

Если я получил такое определение службы:

[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, но исключение, перехваченное в моем обработчике ошибок, всегда имеет тот же тип, что и исключение, которое я выдал.

Я неправильно понимаю все это поведение ядовитых сообщений? Я думал, что если мой код обработки сообщений выдаст необработанное исключение, тогда это исключение окажется MsmqPoisonMessageException, потому что в противном случае у меня не было бы шанса получить идентификатор поиска msg в очереди.

Спасибо вам всем.


person David    schedule 19.06.2009    source источник


Ответы (2)


WCF инкапсулирует исключения в исключение ошибки.

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

Вы также должны указать, какие исключения должны вызываться в интерфейсе/контракте.

person Shiraz Bhaiji    schedule 28.06.2009

Прежде всего, вам нужно извлекать сообщения внутри транзакции, иначе они не будут помещены обратно в очередь, когда из вашего кода возникнет исключение. Добавьте это в функцию ProcessMessage:

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

Кроме того, вам необходимо убедиться, что привязка настроена на ошибку при обнаружении подозрительных сообщений, а число повторных попыток и время достаточно малы, чтобы вы могли увидеть это при тестировании.

Попробуйте выполнить следующие действия (используя VS 2008):

  1. Откройте инструмент настройки WCF для вашего файла app.config.
  2. Выберите «Привязки» в дереве и нажмите «Новая конфигурация привязки» в области задач.
  3. Выберите тип привязки вашей конечной точки (возможно, netMsmqBinding или msmqIntegrationBinding).
  4. Задайте имя новой конфигурации привязки
  5. Задайте для свойства ReceiveErrorHandling значение «Ошибка».
  6. Задайте для свойства ReceiveRetryCount значение 2.
  7. Установите RetryCycleDelay на «00:00:10».
  8. Выберите конечную точку для службы и задайте для конфигурации привязки имя, указанное на шаге 4.

(Возможно, вам понадобятся другие значения для ReceiveRetryCount и RetryCycleDelay для вашей производственной конфигурации.)

person Jesse McDowell    schedule 28.07.2009