Как изменить WCF для обработки сообщений в другом (не -мыльном) формате?

StackOverflow https://stackoverflow.com/questions/4437660

  •  09-10-2019
  •  | 
  •  

Вопрос

Я работаю с WCF, чтобы обмениваться сообщениями с сторонней компанией. Сообщения должны быть отправлены и получены в конверте, который соответствует Спецификация EBXML. Анкет В идеале я хотел бы использовать как можно больше стека WCF и избежать один метод для их обработки всех Подход, как в этом случае, это означало бы написание большей части инфраструктуры WCF снова.

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

Я смог найти много подробных документов в отдельных реализациях каждой из них, но очень мало о том, как собрать все это вместе в конце. Казалось бы, что книги, которые у меня есть, также легки на эти темы без упоминания об этом в «Pro WCF» от Peiris и Mulder.

Я стремлюсь к следующему.

Отправляемые и полученные сообщения должны быть отформатированы, как ниже, где имя первого элемента является именем операции, которая должна быть выполнена, и дочерний элемент является полезной нагрузкой сообщения запроса из формы:

<?xml version="1.0" encoding="UTF-8"?>
<op:DoSomething xmlns:op="http://my.ebXML.schema.com" xmlns:payload="http://payload.company.com">
    <op:AnObject>
        <payload:ImportantValue>42</payload:ImportantValue>
    </op:AnObject>
</op:DoSomething>

И ответ будет:

<?xml version="1.0" encoding="UTF-8"?>
<op:AcknowledgementResponse xmlns:op="http://my.ebXML.schema.com" xmlns:payload="http://payload.company.com">
    <op:ResponseObject>
        <payload:Ok>True</payload:Ok>
    </op:ResponseObject>
</op:AcknowledgementResponse>

Поскольку все сообщения описываются схемами XML, я использовал xsd.exe, чтобы преобразовать их в сильно напечатанные объекты. Видеть https://gist.github.com/740303 для схем. Обратите внимание, что это примеры схемы. Я не могу опубликовать реальные схемы, не нарушая соглашения о конфиденциальности клиентов (при этом вы не хотите меня, так как они огромны).

Теперь я хотел бы иметь возможность написать реализацию службы следующим образом:

public class MyEndpoint : IMyEndpoint
{
    public AcknowledgementResponse DoSomething(AnObject value)
    {
        return new AcknowledgementResponse
            {
                Ok = True;
            };
    }
}

Любая помощь приветствуется.

Это было полезно?

Решение

Я не думаю, что вам нужно что -то делать с привязками. Я предполагаю, что вам все равно нужно отправить форматированное сообщение EBXML через HTTP?

@Ladislav's Ответ является одним из подходов, но я думаю, что кодеры сообщений предназначены для работы на гораздо более низком уровне, чем то, чего вы пытаетесь достичь. По сути, части, которые кодируют сообщения в базовый поток и обратно (то есть, как сообщение представлено как байты на потоке).

Я думаю, что вам нужно сделать, это реализовать Пользовательский форматер сообщений. Анкет В частности, поскольку вы говорите, что хотите отправить сообщения на третью сторону, тогда я думаю, что это только IClientMessageFormatter интерфейс, который вам понадобится для реализации. Другой интерфейс (IDispatchMessageFormatter) используется на стороне сервера.

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

После реализации вы можете использовать подход «Один метод для обработки их всех» для тестирования и отладки вашего форматера. Просто возьмите полученное сообщение и выбросьте его на консоль для просмотра, а также отправьте ответ EBXML. Вы также можете использовать тот же подход для создания вашего единичного тестирования.

Другие советы

Подробная информация о моей реализации ответа Тима

Мне нужно было написать это для клиента, на которого я сейчас работаю, поэтому я подумал, что могу также опубликовать это здесь. Надеюсь, это кому -то поможет. Я создал образец клиента и сервис, который я использовал, чтобы попробовать некоторые из этих идей. Я очистил его и добавил в GitHub. Ты сможешь Загрузите его здесь.

Следующие вещи, необходимые для реализации, чтобы позволить WCF использоваться так, как мне потребовалось:

  1. WCF не ожидать сообщения SOAP
  2. Возможность форматировать запросы и ответные сообщения точно по мере необходимости
  3. Все сообщения, которые необходимо учитывать для обработки
  4. Входящие сообщения, которые должны быть направлены на правильную операцию, чтобы справиться с ними

1. Настройте WCF, чтобы не ожидать сообщения SOAP

Первым шагом было получение входящего сообщения через TextMessageEncoder. Это было достигнуто с помощью пользовательской привязки с настройкой MessageVersion.NONE на элементе TextMessageEncoding.

  <customBinding>
    <binding name="poxMessageBinding">
      <textMessageEncoding messageVersion="None" />
      <httpTransport />
    </binding>
  </customBinding>

2. Правильно отформатируйте сообщение

Форматтер сообщений требуется, так как входящее сообщение отказалось от деосиализации существующим форматером XML без добавления дополнительных атрибутов в контракты сообщения. Обычно это не было бы проблемой, но запуск моих клиентов схемы EBXML через XSD.Exe генерирует файл CS 33000, и я не хотел изменять это каким -либо образом. Кроме того, люди забудут повторно добавить атрибуты в будущем, так что это, мы надеемся, тоже облегчит обслуживание.

Пользовательский форматер рассчитывает преобразовать входящее сообщение в тип первого параметра и преобразовать тип возврата в сообщение ответа. Он осматривает метод реализации, чтобы определить типы первого параметра и возвращаемого значения в конструкторе.

public SimpleXmlFormatter(OperationDescription operationDescription)
{
    // Get the request message type
    var parameters = operationDescription.SyncMethod.GetParameters();
    if (parameters.Length != 1)
        throw new InvalidDataContractException(
"The SimpleXmlFormatter will only work with a single parameter for an operation which is the type of the incoming message contract.");
    _requestMessageType = parameters[0].ParameterType;

    // Get the response message type
    _responseMessageType = operationDescription.SyncMethod.ReturnType;
}

Затем он просто использует XmlSerializer для сериализации и десериализации данных. Интересной частью этого для меня было использование пользовательского тела для сериализации объекта в объект сообщения. Ниже является часть реализации для сервисного сериализатора. Реализация клиента является обратной.

public void DeserializeRequest(Message message, object[] parameters)
{
    var serializer = new XmlSerializer(_requestMessageType);
    parameters[0] = serializer.Deserialize(message.GetReaderAtBodyContents());
}

public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
    return Message.CreateMessage(MessageVersion.None, _responseMessageType.Name,
                                 new SerializingBodyWriter(_responseMessageType, result));
}

private class SerializingBodyWriter : BodyWriter
{
    private readonly Type _typeToSerialize;
    private readonly object _objectToEncode;

    public SerializingBodyWriter(Type typeToSerialize, object objectToEncode) : base(false)
    {
        _typeToSerialize = typeToSerialize;
        _objectToEncode = objectToEncode;
    }

    protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
    {
        writer.WriteStartDocument();
        var serializer = new XmlSerializer(_typeToSerialize);
        serializer.Serialize(writer, _objectToEncode);
        writer.WriteEndDocument();
    }
}

3. Обработайте все входящие сообщения

Чтобы указать WCF, чтобы все входящие сообщения были обработаны, мне нужно было установить свойство ContractFilter на EndPointDispatcher на экземпляр MatchallMessageFilter. Вот фрагмент, иллюстрирующий это из моей конфигурации поведения конечной точки.

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
    endpointDispatcher.ContractFilter = new MatchAllMessageFilter();
    // Do more config ...
}

4. Выбор правильной работы

Это было достигнуто путем создания класса, который реализует Idispatchoperationselector. В методе Selectoperation я осматриваю входящее сообщение. Здесь я ищу две вещи: 1. Убедитесь, что пространство имен корневого элемента совпадает с пространством имен контракта на обслуживание 2. Имя корневого элемента (обратите внимание на использование LocalName для удаления любого префикса пространства имен. )

Имя корневого элемента - это возвратное значение, которое будет отображаться с любой операцией в контракте с соответствующим именем или где атрибут действия имеет соответствующее значение.

public string SelectOperation(ref Message message)
{
    var messageBuffer = message.CreateBufferedCopy(16384);

    // Determine the name of the root node of the message
    using (var copyMessage = messageBuffer.CreateMessage())
    using (var reader = copyMessage.GetReaderAtBodyContents())
    {
        // Move to the first element
        reader.MoveToContent();

        if (reader.NamespaceURI != _namespace)
            throw new InvalidOperationException(
"The namespace of the incoming message does not match the namespace of the endpoint contract.");

        // The root element name is the operation name
        var action = reader.LocalName;

        // Reset the message for subsequent processing
        message = messageBuffer.CreateMessage();

        // Return the name of the action to execute
        return action;
    }
}

Завершая все это

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

Для меня одним интересным открытием было то, что поведение конечной точки может установить форматер сообщений для всех операций в конечной точке для использования пользовательского форматета сообщений. Это экономит необходимость настройки их отдельно. Я взял это из одного из Microsoft образцы.

Полезные ссылки на документацию

Лучшие ссылки, которые я обнаружил до сих пор, - это статьи в журнале MSDN Станции MSDN (Google »Сайт: MSDN.microsoft.com Станция обслуживания WCF»).

Привязки WCF в глубине - Очень полезная информация о настройке привязки

Расширение WCF с помощью пользовательского поведения - Лучший источник информации о точках интеграции диспетчеров, который я еще обнаружил, и они содержат несколько действительно полезных диаграмм, которые иллюстрируют все точки интеграции и где они встречаются в порядке обработки.

Microsoft WCF Образцы - Здесь много, что не очень хорошо задокументировано в другом месте. Я нашел чтение через исходный код для некоторых из этих очень поучительных.

Для пользовательского формата сообщений вам нужен пользовательский MessageEncoder. MSDN Содержит пример, как создать пользовательский энкодер. Если вы используете Отражатель Вы найдете несколько реализаций Encoder, чтобы вы могли научиться писать.

Вы также можете проверить, что произойдет, если вы попытаетесь использовать TextmessageEncoder с MessageVersion.none (я никогда не пробовал).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top