Обработка ошибок при взаимодействии MassTransit с неправильными форматами JSON

avatar
Daniel
9 августа 2021 в 07:18
178
0
0

Мы используем клиенты, отличные от .NET, для интеграции некоторых наших общедоступных API с серверными службами .NET с использованием взаимодействия MassTransit, и периодически мы получаем запросы, которые не соответствуют спецификации сообщения (например, клиент предоставляет строку, в которой мы ожидать объект). Это приводит к ArgumentExceptions в очереди xxx_error, как и ожидалось, и я вижу исходное сообщение с ошибочными свойствами. Я надеялся, что есть способ использовать и обрабатывать их, чтобы я мог «вручную» десериализовать их, проверять некоторые их свойства и уведомлять клиентов о том, что они отправляют ошибочные сообщения.

Я попытался использовать потребителя, который обрабатывает Fault<T> для типа сообщения, однако, похоже, он также полагается на успешную десериализацию сообщения и никогда не вызывается. Сообщения, которые меня интересуют, имеют общий базовый интерфейс, и я попытался создать потребитель ошибок для этого интерфейса, надеясь обойти десериализацию, но этот потребитель ошибок, похоже, никогда не вызывается.

Я также пытался использовать неуниверсального Fault потребителя, который действительно получает сообщение, однако, если я использую этого потребителя, у меня нет возможности добраться до исходного ошибочного сообщения, чтобы я мог его проверить. Если я проверяю содержимое сообщения, используя context.ReceiveContext.GetBody(), оно имеет свойства сообщения об ошибке и исключение, но не детали исходного сообщения. Следовательно, использование либо TryGetMessage(), либо TryGetPayload() возвращает false.

Пример кода для иллюстрации того, о чем я говорю:

// base interface
public interface IFoo { 
  Bar Bar { get; }
}

// message class
public class Foo : IFoo {
  public Bar Bar { get; set; }
}

// foo fault consumer - never called
public class FooFaultConsumer : IConsumer<Fault<Foo>>
{
  public Task Consume(ConsumeContext<Fault<Foo>> context) => context.CompleteTask;
}

// ifoo fault consumer - also never called
public class FooInterfaceFaultConsumer : IConsumer<Fault<IFoo>>
{
  public Task Consume(ConsumeContext<Fault<IFoo>> context) => context.CompleteTask;
}

// non-generic fault consumer - called but no details available
public class FaultConsumer : IConsumer<Fault>
{
  public Task Consume(ConsumeContext<Fault> context)
  {
    context.TryGetMessage(out IFoo _); // returns false
    context.TryGetMessage(out Foo _); // returns false
    context.TryGetPayload(out IFoo _); // returns false
    context.TryGetPayload(out Foo _); // returns false
    context.ReceiveContext.TryGetPayload(out IFoo _); // returns false
    context.ReceiveContext.TryGetPayload(out Foo _); // returns false

    var body = Encoding.UTF8.GetString(context.ReceiveContext.GetBody());

    // body is a JSON string with a message property that only has Fault properties 
    // it does not contain any of the original message properties
  }
}
// registrations
cfg.ReceiveEndpoint(e => {
  e.Consumer<FooFaultConsumer>();
  e.Consumer<FooInterfaceFaultConsumer>();
});

Пример ошибочного сообщения, в котором Bar является строкой, а не объектом (сообщение упаковано в заголовки MassTransit).

{
  "bar" : "foobar"
}

Есть ли элегантный способ обработки ошибок десериализации JSON и получения копии сообщения в том виде, в котором оно появляется в очереди ошибок? Я отмечаю, что документация MassTransit не рекомендует помещать потребителей в эти очереди.

Источник

Ответы (0)