Я правильно понял MsmqPoisonMessageException? - PullRequest
1 голос
/ 19 июня 2009

Если я получил определение сервиса, подобное этому:

[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 волшебным образом инкапсулирует мое «новое исключение (« Test »)» в MsmqPoisonMessageException, но исключение, обнаруженное в моем обработчике ошибок, всегда имеет тот же тип, что и исключение, которое я выдал.

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

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

Ответы [ 2 ]

1 голос
/ 28 июля 2009

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

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

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

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

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

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

1 голос
/ 28 июня 2009

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

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

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

...