Pregunta

Estoy trabajando con WCF para intercambiar mensajes con una tercera empresa. Los mensajes deben ser enviados y recibidos en un sobre que coincide con el ebXML especificación . Idealmente me gustaría utilizar como gran parte de la pila WCF como sea posible y evitar la un método para procesarlos todo el acercamiento como en este caso, eso significaría escribir gran parte de la infraestructura de WCF de nuevo.

Por lo que puedo ver desde mi investigación inicial que esto me requieren para escribir mi propia unión costumbre pero estoy luchando para encontrar la claridad en la documentación de MSDN.

he sido capaz de encontrar un montón de documentos detallados acerca de las implementaciones individuales de cada uno de ellos, pero muy poco sobre cómo poner todo junto extremo a extremo. Parecería que los libros que tengo son igualmente luz sobre estos temas también sin ninguna mención de esto en "Pro WCF" por Peiris y Mulder.

Lo que mi objetivo es algo así como lo siguiente.

Los mensajes que se envían y se reciben deben formatearse como por debajo de donde el nombre del primer elemento es el nombre de la operación que se va a ejecutar y el elemento de niño es la carga útil del mensaje de petición sería de la forma:

<?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>

Y la respuesta sería:

<?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>

A medida que los mensajes están descritas por los esquemas XML he utilizado XSD.exe para convertir éstos a los objetos inflexible. Ver https://gist.github.com/740303 de los esquemas. Tenga en cuenta que estos son ejemplos de esquemas. No soy capaz de publicar los esquemas reales sin violar los acuerdos de confidencialidad del cliente (ni lo que me quiero también, ya que son enormes).

Ahora me gustaría ser capaz de escribir la implementación del servicio de la siguiente manera:

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

Cualquier ayuda sería muy apreciada.

¿Fue útil?

Solución

No creo que usted tiene que hacer nada con fijaciones. Estoy asumiendo que usted necesita para enviar el mensaje con formato ebXML través de HTTP de todos modos?

respuesta

@ Ladislav es uno de los enfoques, pero creo que los codificadores de mensajes están diseñados para funcionar a un nivel mucho más bajo de lo que estamos tratando de lograr. Son esencialmente las piezas que codifican los mensajes desde y hacia la corriente subyacente (es decir, cómo el mensaje se representa como bytes en la corriente).

Creo que lo que hay que hacer es poner en práctica un costumbre Mensaje formateador . En particular, ya que se dice que desea enviar los mensajes a un tercero, entonces yo creo que es sólo la interfaz IClientMessageFormatter que tendrá que poner en práctica. La otra interfaz (IDispatchMessageFormatter) se utiliza en el lado servidor.

También tendrá que implementar un ServiceBehavior y OperationBehavior apropiado para instalar el formateador en la pantalla, pero el código para esto será mínimo (la mayor parte del código estará en la implementación de la interfaz anterior mencionado).

Una vez implementado, se puede utilizar el "un método para procesarlas para todos" a prueba y depurar el formateador. Simplemente tome el mensaje recibido y lo descarga en la consola para su revisión, y luego también enviar una respuesta de vuelta ebXML. También es posible usar el mismo enfoque para construir su unidad de pruebas.

Otros consejos

Detalles de mi aplicación de la respuesta de Tim

que necesitaba escribir esto para el cliente actualmente estoy trabajando para, así que pensé que también podría publicarlo aquí también. Espero que esto ayude a alguien. He creado un cliente de ejemplo y el servicio que he usado para probar algunas de estas ideas. He limpiado para arriba y añadí a github. Puede descargarlo aquí .

Las siguientes cosas necesarias para ser implementado para permitir WCF para ser utilizado de la manera que yo requería:

  1. WCF no puede esperar un mensaje SOAP
  2. La capacidad para dar formato a los mensajes de solicitud y respuesta exactamente como se requiere
  3. Todos los mensajes a ser considerado para el procesamiento
  4. Los mensajes entrantes sean encaminadas a la correcta operación de manejarlos

1. Configurar WCF para no esperar un mensaje SOAP

El primer paso estaba recibiendo el mensaje entrante a través de la TextMessageEncoder. Esto se logró mediante el uso de una unión con el ajuste MessageVersion.None en el elemento textMessageEncoding personalizado.

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

2. Formatear correctamente el mensaje

El mensaje formateador se requiere que el mensaje entrante se negó a ser de-serializado por el formateador XML existente sin la adición de atributos adicionales en los contratos de mensajes. Esto no sería un problema, pero normalmente se ejecuta ebXML mis clientes a través de esquemas XSD.exe genera un archivo cs 33000 línea y yo no quiero tener que modificar esto de ninguna manera. Además la gente se olvide de volver a agregar los atributos en el futuro, así que esto es de esperar hace que el mantenimiento más fácil también.

El formateador personalizado espera para convertir el mensaje entrante con el tipo del primer parámetro y para convertir el tipo de retorno en un mensaje de respuesta. Se inspecciona el método de ejecución para determinar los tipos de primer parámetro y valor de retorno en el constructor.

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;
}

A continuación, simplemente utiliza el XmlSerializer para serializar y deserializar los datos. Una parte interesante de esto para mí fue el uso de un BodyWriter personalizada para serializar el objeto en el objeto del mensaje. A continuación se muestra parte de la implementación para el serializador servicio. La aplicación cliente es a la inversa.

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. Procesar todos los mensajes entrantes

Con el fin de instruir a WCF para permitir que todos los mensajes entrantes a ser procesados ??que necesitaba para establecer la propiedad ContractFilter en el endpointDispatcher a una instancia de la MatchAllMessageFilter. Aquí hay un fragmento que ilustra esto desde la configuración de mi comportamiento de punto final.

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

4. Al seleccionar el correcto funcionamiento

Esto se logró mediante la creación de una clase que implementa IDispatchOperationSelector. En el método SelectOperation inspecciono el mensaje entrante. Aquí estoy buscando dos cosas: 1. Una comprobación de validez que el espacio de nombres del elemento raíz es la misma que el espacio de nombres del contrato de servicios 2. El nombre del elemento raíz (nótese el uso de LocalName eliminar cualquier prefijo de espacio)

El nombre del elemento raíz es el valor de retorno y que se proyectará en cualquier operación en el contrato con un nombre coincidente, o cuando el atributo de acción tiene un valor coincidente.

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;
    }
}

envolviéndolo todo para arriba

Para hacer más fácil la implementación creé un comportamiento de punto final para manejar la configuración del selector formateador de mensajes, el filtro y el funcionamiento del contrato. También podría haber creado una unión a concluir la configuración de enlace de encargo, pero no pensé que una parte era demasiado difícil de recordar.

Un descubrimiento interesante para mí fue que el comportamiento de punto final puede configurar los mensajes formateador para todas las operaciones en el punto final a usar un formateador de mensaje personalizado. Esto ahorra la necesidad de configurar por separado. Elegí este a partir de uno de los Microsoft muestras .

Documentación Enlaces útiles

Los mejores referencias que he encontrado hasta el momento son la estación de servicio de MSDN artículos de revistas (Google "site: msdn.microsoft.com WCF estación de servicio")

.

WCF enlaces en profundidad - información muy útil sobre la configuración de los enlaces de

La extensión WCF con comportamientos personalizados - La mejor fuente de información sobre las puntos despachador de integración que todavía no he encontrado y contienen algunos diagramas realmente útiles que ilustran todos los puntos de integración y donde se dan en el orden de procesamiento.

muestras Microsoft WCF - Hay mucho aquí que no se documenta muy bien en otros lugares. Me encontré leyendo el código fuente de algunos de ellos muy instructivo.

Para el formato de mensaje personalizado que necesita personalizada MessageEncoder . MSDN contiene ejemplo cómo crear codificador personalizado. Si utiliza Reflector se encuentran varias implementaciones del codificador para que pueda aprender cómo escribirlo.

También puede comprobar lo que ocurrirá si se intenta utilizar TextMessageEncoder con MessageVersion.None (nunca he tryed).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top