4

与えられたクラス:

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

WireShark は、WCF TCP バインディングを介して送信された場合、メッセージのエンコードがバイナリであることを示しています (印刷可能な文字のみですが、アイデアは得られます)。

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

しかし、このタイプのインスタンスを次のようにシリアル化すると...

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

...その後、ストリームには次のような SOAP XML が含まれます。

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

私の質問は、自分のコードでこのバイナリ表現を生成するように制御するにはどうすればよいですか?DataContractSerializer

余談として:

ご覧のとおり、objectプロパティの型をエンコードする必要があるため (つまり URI)、メッセージが肥大化しています。これを変更して、カスタム バイナリ エンコーディングを使用します。私のシナリオでは、フィールド ID によって型が決まります (この場合はdouble)。

4

4 に答える 4

1

DataContractSerializer を制御することはできませんが、テキスト形式またはバイナリにシリアル化するかどうかは、WCF バインディングで制御できます。

お気づきのとおり、NetTcpBinding はデフォルトでバイナリであるため、非常にコンパクトで高速です。Http ベースのバインディングは、相互運用性のためにデフォルトで Text に設定されているため、より冗長でパフォーマンスが低下します。

しかし、独自のバイナリ ベースの HTTP バインディングを作成することを妨げるものは何もありません。そうする場合、外部クライアントとの相互運用性が窓の外にあることを受け入れる意思がある場合。これは、同じカスタム バインディングを使用する独自の内部クライアントでのみ機能します。

基本的に、コードまたは構成で独自のカスタム バインディングをゼロから作成する必要があります。構成では、それは非常に簡単です:

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

指定する必要がある最小限の部分は、メッセージ エンコーディングとトランスポート プロトコルの 2 つです。それ以外はオプションです。

これで、WCF サービスとクライアントを指定して、この新しいカスタムのバイナリ オーバー HTTP バインディングを使用できるようになります。

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

<client>(もちろん、同じことがセクションのクライアントにも当てはまります)。

これで、コード内の DataContractSerializer を何らかの方法、形状、形式で制御することは問題ではなく、カスタム バインディングを作成して使用するだけです。

マルク

編集(コメントを残した後):
まあ、WCF は確かに非常に拡張性があるため、クライアントから出る途中でメッセージ インスペクタのようにこれを行うことができます。メッセージを検査し、そのサイズを測定し、それをファイルまたはデータベースに書き込むだけのメッセージ インスペクター ( IClientMessageInspectorから派生) を作成できます。

于 2009-07-02T15:12:21.540 に答える
0

これが私が問題に対して見つけることができる最も簡単な解決策です:

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

...ここで、encodingパラメーターは次のいずれかです。

new TextMessageEncodingBindingElement()

...また...

new BinaryMessageEncodingBindingElement()

...テキスト形式とバイナリ形式のどちらが必要かによって異なります。

このトピックに関する記事へのリンクを提供してくれたtomasrに感謝します。

于 2009-07-30T14:06:38.573 に答える