Frage

Bei einer Klasse:

[DataContract]
public sealed class ChangedField
{
    [DataMember(Name="I")] public ushort FieldId { get; set; }
    [DataMember(Name="V")] public object Value { get; set; }
}

Wireshark zeigt, dass, wenn sie über eine WCF TCP-Bindung, die Codierung der Nachricht in binär gesendet (druckbare Zeichen nur, aber Sie erhalten die Idee):

  

ChangedFielda.I..a.V....e:double..e http://www.w3.org/2001/XMLSchema.s.....a.

Aber wenn ich eine Instanz dieses Typs serialise wie so ...

var ser = new DataContractSerializer(typeof(ChangedField));
var stream = new MemoryStream();
ser.WriteObject(stream, new ChangedField { FieldId = 1, Value = 1.23d });

... dann enthält der Strom SOAP XML ähnelt dies:

<ChangedField>
  <I>1</I>
  <V i:type="a:double" xmlns:a="http://www.w3.org/2001/XMLSchema">1.23</V>
</ChangedField>

Also meine Frage ist, wie kann ich steuern DataContractSerializer diese binäre Darstellung in meinem eigenen Code zu produzieren?

Als Nebenwirkung:

Wie Sie sehen können, wird die Nachricht durch die Tatsache, dass die aufgeblähten object Eigenschaft seiner Art (daher die URI) codiert hat. Ich werde dies eine benutzerdefinierter binäre Codierung verwenden, um zu ändern, wie es in meinem Szenario, das Feld ID die Art bestimmt (in diesem Fall double).

War es hilfreich?

Lösung

die TCP-Bindung verwendet die binäre Nachricht Encoder standardmäßig wo, wie Sie nur den Datenvertrag in XML in Ihrem zweiten Beispiel Serialisierung. Was mit dem binären Nachricht Encoder passiert ist, dass es im Grunde den Datenvertrag Serializer mit einer benutzerdefinierten XmlWriter Implementierung bereitstellt, die ein proprietären Binärformat erzeugt, anstelle von XML.

Wenn Sie dies mit einer anderen Bindung verwenden möchten (beispielsweise HTTP), dann müssen Sie eine benutzerdefinierte erstellen Bindung statt und fügen Sie die BinaryMessageEncodingElement Element anstelle des normalen TextMessageEncodingElement.

Andere Tipps

Sie können nicht die DataContractSerializer steuern -. Sie können jedoch in Ihrer WCF steuern verbindlich, ob es in Textformat oder binär serialisiert werden

Wie Sie selbst bemerkt haben, NetTcpBinding standardmäßig binär und daher ist sehr kompakt und schnell. Der Http-basierten Bindungen Standard für die Interoperabilität willen Text und deshalb ist ausführlicher und weniger performant.

Aber es gibt nichts mehr im Weg steht Ihre eigene binäre-basierte HTTP-Erstellung Bindung - IF Sie sind bereit, zu akzeptieren, dass die Interoperabilität mit externen Kunden aus ist das Fenster, wenn Sie das tun. Dies wird nur mit Ihren eigenen internen Kunden arbeiten, die die gleichen benutzerdefinierte Bindung verwenden.

Im Grunde, was Sie tun müssen, ist Ihre eigenen von Grund auf Bindung aufzubauen - in Code oder Config. In Config ist es ziemlich einfach:

<system.serviceModel>
  <bindings>
     <customBinding name="binaryHttpBinding">
        <binaryMessageEncoding />
        <httpTransport />
     </customBinding>
  </bindings>
</system.serviceModel>

Die beiden Mindest Teile Sie müssen angeben sind ein Nachrichtencodierung und ein Transportprotokoll -. Alles andere ist optional

Jetzt können Sie Ihre WCF-Dienst und Client festlegen, damit sie diese neue verwenden werden, benutzerdefinierte binary-over-HTTP-Bindung:

<system.serviceModel>
   <services>
      <service name="YourService">
         <endpoint address="http://whatever.com:8888/YourAddress"
                   binding=binaryHttpBinding"
                   contract="IYourContract" />
      </service>
   </services>
</system.serviceModel>

(und das gleiche funktioniert auch für die Kunden im <client> Abschnitt, natürlich).

Da haben Sie es - es ist nicht eine Frage des DataContractSerializer in Ihrem Code in irgendeiner Weise oder Form zu steuern -. Erstellen Sie einfach eine benutzerdefinierte Bindung und es verwenden,

Marc

Bearbeiten (nach Kommentar links):
Nun, WCF ist in der Tat sehr dehnbar, so dass Sie auf dem Weg, um diese wie Nachrichteninspektoren tun aus dem Client. Sie könnten eine solche Nachricht Inspektor (abgeleitet von IClientMessageInspector ), der tut nichts anderes als die Botschaft seiner Größe, dass in einer Datei oder Datenbank

Haben Sie lesen Sie die Dokumentation auf der DataContractSerializer

  

die DataContractSerializer zu verwenden,   zuerst eine Instanz einer Klasse erstellen   und ein Objekt angemessen Schreib   oder das Lesen des Formats; zum Beispiel ein   Instanz des XmlDictionaryWriter.   Dann rufen Sie die Writeobject-Methode   beharren die Daten. Zum Abrufen von Daten,   Erstellen eines Objekts angemessen   Lesen der Datenformat (beispielsweise ein   XmlDictionaryReader für eine XML   Dokument) und rufen Sie die Readobject   Verfahren.

Sie werden dann über XmlDictionaryWriter .

Hier ist die einfachste Lösung, die ich für das Problem gefunden:

static byte[] Serialise(object obj, MessageEncodingBindingElement encoding)
{
    encoding.MessageVersion = MessageVersion.Soap12;
    var stream = new MemoryStream();
    var message = Message.CreateMessage(MessageVersion.Soap12, "", obj, 
       new DataContractSerializer(obj.GetType()));
    encoding.CreateMessageEncoderFactory().Encoder.WriteMessage(message, stream);
    return stream.ToArray();
}

... wo der encoding Parameter ist entweder:

new TextMessageEncodingBindingElement()

... oder ...

new BinaryMessageEncodingBindingElement()

... je nachdem, ob Sie Text oder Binär-Formatierung.

Dank tomasr für die Link zu seinem Beitrag zu diesem Thema .

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