Inside Windows Communication Foundation を読んでいてXmlDictionaryWriterを使用して、xml形式のデータをエンコードした結果どのようなバイト数になるのかなど掲載されていたので、自分で試した結果を掲載しています。本のまんまの例ではありません。

確認環境

  • 動作環境:Windows Server 2003, .NET3.5SP1
  • 開発環境:Visual Studio 2008 Professional

 今回は、 XmlDictionaryWriter のファクトリ CreateDictionaryWriter , CreateTextWriter , CreateMtomWriter , CreateBinaryWriter を使用して XmlDictionaryWriter を作成しエンコーディング結果とバイト数を確認してみます。

1. CreateDictionaryWriter

XmlWriter のインスタンスを引数にとってXmlDictionaryWriterのインスタンスを作成します。作成されるのはXmlWriter のラッパークラスのインスタンスです。メソッドの引数などに、 XmlWriter ではなく、 XmlDictionaryWriter が必要な状況が発生した場合に利用できます。

使用サンプルは次のとおり

public static void CrateWriterTest()
{
    MemoryStream stream = new MemoryStream();
    XmlWriterSettings setting = new XmlWriterSettings();
    setting.Encoding = new UTF8Encoding(false); // BOMを出力しないようにする
     XmlWriter xw = XmlWriter.Create(stream, setting);
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateDictionaryWriter(xw))
    {
        writer.WriteStartDocument();
        writer.WriteElementString("greet", "urn:hc", "Hello WCF!!");
        writer.Flush();

    }
    Console.WriteLine("XmlDictionaryWriter.CreateTextWriter UTF-8エンコードでのバイト数 {0} bytes", stream.Position);
    byte[] bytes = stream.ToArray();
    //Console.WriteLine(Convert.ToBase64String(bytes));
    Console.Write(BitConverter.ToString(bytes));
    stream.Position = 0;
    Console.WriteLine("書き込みデータの内容");
    Console.WriteLine("{0}", new StreamReader(stream).ReadToEnd());
    stream.Close();
}

出力結果は次のようになります。

2.CreateTextWriter

XMLをテキスト形式でエンコーディングするXmlDictionaryWriterのインスタンスを作成します。サポートされているのはUTF8とUTF16ビッグエンディアン、リトルエンディアンです。

使用サンプルは次のとおり

public static void CreateTextWriterTest()
{
    MemoryStream stream = new MemoryStream();
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, Encoding.UTF8, false))
    {
        writer.WriteStartDocument();
        writer.WriteElementString("greet", "urn:hc", "Hello WCF!!");
        writer.Flush();
    }

    Console.WriteLine("XmlDictionaryWriter.CreateTextWriter UTF-8エンコードでのバイト数 {0} bytes", stream.Position);
    byte[] bytes = stream.ToArray();
    //Console.WriteLine(Convert.ToBase64String(bytes));
    Console.Write(BitConverter.ToString(bytes));
    stream.Position = 0;
    Console.WriteLine("書き込みデータの内容");
    Console.WriteLine("{0}", new StreamReader(stream).ReadToEnd());
    stream.Close();
} 

出力結果は次のようになります。バイト数は79バイト。CreateDictionaryWriterメソッドでXmlDictionaryWriterのインスタンスを作成した場合と同じ結果になっていることが分かります。

3.CreateMtomWriter

XMLをMTOM形式でエンコーディングするXmlDictionaryWriterのインスタンスを作成します。

使用サンプルは次のとおり

public static void CreateMtomWriterTest()
{
    MemoryStream stream = new MemoryStream();
    //using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateMtomWriter(stream, Encoding.UTF8, 100, "Application/soap+xml", "boundary", "urn:startUri", true, false))
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateMtomWriter(stream, Encoding.UTF8, 100, "Application/soap+xml"))
    {
        writer.WriteStartDocument();
        writer.WriteElementString("greet", "urn:hc", "Hello WCF!!");
        writer.Flush();

        Console.WriteLine("XmlDictionaryWriter.CreateMtomWriter UTF-8エンコードのバイト数{0} bytes", stream.Position);
        byte[] bytes = stream.ToArray();
        Console.Write(BitConverter.ToString(bytes));
        stream.Position = 0;
        Console.WriteLine("書き込みデータの内容");
        Console.WriteLine("{0}", new StreamReader(stream).ReadToEnd());
        stream.Close();
    }
}

 出力結果は次のようになります。データ量が少ない場合、MTOMエンコーディングの場合、Text形式よりも大きなデータになってしまうことが分かります。

4.CreateBinaryWriter

XMLをバイナリ形式でエンコーディングするXmlDictionaryWriterのインスタンスを作成します。

使用サンプルは次のとおり

public static void CreateBinaryWriterTest()
{
    MemoryStream stream = new MemoryStream();
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream))
    {
        writer.WriteStartDocument();
        writer.WriteElementString("greet", "urn:hc", "Hello WCF!!");
        writer.Flush();

        Console.WriteLine("XmlDictionaryWriter.CreateMtomWriter のバイト数{0} bytes", stream.Position);
        byte[] bytes = stream.ToArray();
        Console.Write(BitConverter.ToString(bytes));
        stream.Position = 0;
        Console.WriteLine("書き込みデータの内容");
        XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, null, new XmlDictionaryReaderQuotas());
        reader.Read();
        Console.WriteLine(reader.ReadString());
        stream.Close();
    }
}

出力結果は次のようになります。エンコーディング後のバイト数は28バイトとなり、効率は圧倒的です。

バイナリエンコーディングはサービス、クライアントがともにWCFの場合のみで使用できます。標準化されるといろいろな場所で使用できるようになるのかなと思います。

さらに、 XmlDictionary を使用すると構文圧縮を行うことができます。ただし、構文圧縮を行ったデータをデシリアライズするには、 XmlDictionaryReader のインスタンスも XmlDictionaryWriter で使用された XmlDictionary と同じデータが格納された XmlDictionary のインスタンスをファクトリメソッドの引数に渡される必要があります。

XmlDictionaryを使用サンプルです。

public static void CreateBinaryWriterWithXmlDictionaryTest()
{
    XmlDictionary dic = new XmlDictionary();
    List<XmlDictionaryString> list = new List<XmlDictionaryString>();
    list.Add(dic.Add("greet"));
    list.Add(dic.Add("urn:hc"));

    MemoryStream stream = new MemoryStream();
    using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream, dic))
    {
        writer.WriteStartDocument();
        writer.WriteElementString(list[0], list[1], "Hello WCF!!");
        writer.Flush();

        Console.WriteLine("XmlDictionaryWriter.CreateMtomWriter のバイト数{0} bytes", stream.Position);
        byte[] bytes = stream.ToArray();
        Console.Write(BitConverter.ToString(bytes));
        stream.Position = 0;
        Console.WriteLine("書き込みデータの内容");
        XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, dic, new XmlDictionaryReaderQuotas());
        reader.Read();
        Console.WriteLine(reader.ReadString());
        stream.Close();
    }
}

 出力結果は次のようになります。

XmlDictionary を使用するとバイト数が17バイトとなり、一番効率よくエンコーディングしていることが分かります。

説明は以上です。