Frage

Ich arbeite mit WCF zu tauschen Nachrichten mit einer Drittfirma. Die Nachrichten müssen in einem Umschlag gesendet und empfangen werden, entspricht die ebXML Spezifikation . Im Idealfall würde Ich mag so viel von dem WCF-Stack wie möglich verwenden und die eine Methode, sie alle Ansatz wie in diesem Fall zu verarbeiten, die wiederum ein Großteil der Infrastruktur des WCF bedeuten würde, zu schreiben.

Soweit ich von meinen ersten Recherchen sehe dies würde mich verlangen meine eigenen benutzerdefinierte Bindung zu schreiben, aber ich habe Schwierigkeiten Klarheit in der Dokumentation in MSDN zu finden.

Ich konnte viele detaillierte Unterlagen über in den einzelnen Implementierungen von jedem von diesen finden, aber sehr wenig darüber, wie es einem Ende zum anderen alle zusammen zu setzen. Es scheint, dass die Bücher, die ich habe auch nicht erwähnt dies in „Pro WCF“ von Peiris und Mulder.

zu diesen Themen in ähnlicher Weise Licht sind

Was ich streben ist so etwas wie die folgenden.

Die Nachrichten gesendet und empfangen werden, müssen wie unten formatiert werden, wo der Name des ersten Elements ist der Name der Operation, die ausgeführt werden soll, und das Kind Element ist die Nutzlast der Anforderungsnachricht von der Form wäre:

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

Und die Antwort wäre:

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

Wie die Nachrichten alle von XML-Schemata beschrieben habe ich XSD.exe verwendet diese stark typisierte Objekte zu konvertieren. Siehe https://gist.github.com/740303 für die Schemata. Beachten Sie, dass diese Beispiel-Schemata. Ich bin die wirklichen Schemata zu schreiben ohne die Verletzung der Client Vertraulichkeitsvereinbarungen nicht in der Lage (oder wollen Sie mich auch, da sie sehr groß sind).

Ich würde jetzt gerne in der Lage sein, die Service-Implementierung zu schreiben, wie folgt:

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

Jede Hilfe wäre sehr willkommen.

War es hilfreich?

Lösung

Ich glaube nicht, dass man alles mit Bindungen tun müssen. Ich gehe davon aus, dass Sie benötigen trotzdem die ebXML-formatierte Nachricht über HTTP senden?

@ ladislav Antwort ist ein Ansatz, aber ich denke Nachricht Encoder an die Arbeit auf einem viel niedrigeren Niveau ausgelegt sind, als das, was Sie erreichen wollen. Sie sind im Wesentlichen der Stücke, die die Nachrichten an und von dem zugrunde liegenden Stream kodieren (das heißt, wie die Nachricht als Bytes im Stream dargestellt wird).

Ich denke, was Sie tun müssen, ist eine benutzerdefinierte Nachricht Formatter . Insbesondere, da Sie sagen, dass Sie die Nachrichten an einen Drittanbieter einreichen möchten, dann denke ich, es ist nur die IClientMessageFormatter Schnittstelle, dass Sie implementieren müssen. Die andere Schnittstelle (IDispatchMessageFormatter) auf der Server-Seite verwendet wird.

Sie werden auch brauchen eine angemessene ServiceBehavior und OperationBehavior zu implementieren, um die Formatierer in den Stapel zu installieren, aber der Code dafür wird minimal sein (der Großteil des Codes wird die oben erwähnte Schnittstelle bei der Umsetzung).

Nach der Implementierung, könnten Sie die „eine Methode, um sie alle zu verarbeiten“ verwenden Ansatz zu testen und zu debuggen Ihre Formatter. Nehmen Sie einfach die empfangene Nachricht und Dump es an die Konsole für Sie heraus zu überprüfen, und dann auch eine ebXML Antwort zurückschicken. Sie könnten auch die gleiche Methode verwenden, Ihre Komponententests aufzubauen.

Andere Tipps

Details meiner Implementierung von Tim Antwort

Ich brauchte diese sich für den Client zu schreiben, ich derzeit arbeite, so dachte ich, ich könnte genauso gut es hier posten zu hoch. Ich hoffe, dass es jemand hilft. Ich habe ein Beispiel-Client und Service geschaffen, die ich verwendet, einige dieser Ideen auszuprobieren. Ich habe es aufgeräumt und es GitHub hinzugefügt. Sie können es hier herunterladen .

Die folgenden Dinge benötigt umgesetzt werden WCF zu ermöglichen, in der Art und Weise verwendet werden, dass ich benötigt:

  1. WCF nicht eine SOAP-Nachricht erwarten
  2. Die Fähigkeit, die Anfrage- und Antwortnachrichten genau formatiert werden je nach Bedarf
  3. Alle Nachrichten für die Bearbeitung
  4. in Betracht gezogen werden
  5. Eingehende Nachrichten auf den korrekten Betrieb geleitet werden, um sie zu behandeln

1. Konfigurieren Sie WCF nicht eine SOAP-Nachricht erwarten

Der erste Schritt war immer die eingehende Nachricht durch die TextMessageEncoder. Dies wurde erreicht, indem ein individuelle Verwendung mit der MessageVersion.None Einstellung auf dem textMessageEncoding Elemente gebunden ist.

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

2. Formatieren Sie die Nachricht korrekt

durch die vorhandenen XML-Formatierer ohne Zusatz von zusätzlichen Attributen auf den Nachrichten Verträge

Der Nachrichtenformatierer erforderlich, da die eingehende Nachricht de-serialisiert werden abgelehnt. Dies würde normalerweise kein Problem sein, aber laufen meine Kunden ebXML-Schemata über XSD.exe eine 33000 Leitung cs-Datei erzeugt, und ich wollte das nicht in irgendeiner Weise zu verändern haben. Neben Menschen vergessen würde, die Attribute in Zukunft erneut hinzufügen, damit diese hoffentlich Wartung erleichtert zu.

Die benutzerdefinierte Formatter erwartet, dass die eingehende Nachricht an den Typ des ersten Parameters konvertieren und den Rückgabetyp in eine Antwortnachricht zu konvertieren. Es überprüft die Umsetzung der Methode, die Arten des ersten Parameters und Rückgabewert im Konstruktor zu bestimmen.

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

Es verwendet dann einfach die XmlSerializer serialisiert werden und die Daten deserialisieren. Ein interessanter Teil davon war für mich die Verwendung eines benutzerdefinierten Bodywriter das Objekt in das Message-Objekt serialisieren. Teil der Umsetzung für den Dienst Serializer ist unten. Die Client-Implementierung ist das Gegenteil.

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. Verarbeiten Sie alle eingehenden Nachrichten

Um WCF zu anweisen, alle eingehenden Nachrichten zu ermöglichen, verarbeitet werden brauchte ich die Contract Eigenschaft auf dem EndpointDispatcher auf eine Instanz des MatchAllMessageFilter einzustellen. Hier ist ein Ausschnitt darstellt, das von meinem Endpunktverhalten Konfiguration.

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

4. Auswählen der richtigen Bedienung

Dies wurde durch die Schaffung einer Klasse, die implementiert IDispatchOperationSelector erreicht. Im SelectOperation Verfahren überprüfe ich die eingehende Nachricht. Hier bin ich für zwei Dinge suchen: 1. Eine Plausibilitätsprüfung, daß der Namensraum des Wurzelelementes ist das gleiche wie der Namensraum des Dienstvertrages 2. Der Name des Wurzelelements (die Verwendung von Local beachten jede Namespacepräfix zu entfernen)

Der Name des Wurzelelementes ist der Rückgabewert, und das wird mit einem passenden Namen auf den Vertrag ein Betriebskennfeld oder wo das Aktionsattribut einen passenden Wert hat.

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

Wrapping It All Up

Um es einfacher zu implementieren ich einen Endpunkt Verhalten erstellt die Konfiguration der Nachrichtenformatierungs, Vertragsfilter und Betriebswahl zu handhaben. Ich hätte auch erstellt eine Bindung die benutzerdefinierte Bindungskonfiguration einpacken, aber ich glaube nicht, dass ein Teil zu schwierig war, sich zu erinnern.

Eine interessante Entdeckung für mich war, dass der Endpunkt Verhalten der Nachrichten-Formatierer für alle Operationen in den Endpunkt festlegen können eine benutzerdefinierte Nachricht Formatierer zu verwenden. Dies erspart die Notwendigkeit, diese separat zu konfigurieren. Ich nahm diese bis von einem der Microsoft Proben .

Hilfreiche Dokumentation Links

Die besten Referenzen, die ich bisher gefunden habe sind die Service Station MSDN Magazin Artikel (Google "site: msdn.microsoft.com Servicestation WCF")

.

WCF Bindings in Tiefen - Sehr nützliche Informationen über die Bindungen der Konfiguration

Erweitern von WCF mit benutzerdefinierten Behaviors - Die beste Quelle für Informationen über Dispatcher Integrationspunkte, dass ich noch nicht gefunden haben, und sie enthalten einige wirklich nützliche Diagramme, die alle Integrationspunkte zeigen und wo sie in der Reihenfolge der Verarbeitung auftreten.

Microsoft WCF Proben - Es gibt eine Menge hier, die nicht sehr gut an anderer Stelle dokumentiert. Ich fand für einige dieser sehr lehrreich durch den Quellcode zu lesen.

Für benutzerdefinierte Nachrichtenformat müssen Sie benutzerdefinierte Message . MSDN enthält Beispiel, wie benutzerdefinierten Encoder erstellen. Wenn Sie Reflector mehrere Encoder-Implementierungen finden, so dass Sie lernen können wie es zu schreiben.

Sie können auch, was überprüfen passieren wird, wenn Sie versuchen, TextMessageEncoder mit MessageVersion.None zu verwenden (ich habe es nie tryed).

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top