web-dev-qa-db-ja.com

XMLをUTF-16ではなくUTF-8として返す方法

<T>をシリアル化するルーチンを使用しています。動作しますが、ブラウザにダウンロードすると空白のページが表示されます。ページのソースを表示したり、テキストエディターでダウンロードを開いたり、xmlを表示したりできますが、それはUTF-16であるため、ブラウザーページに空白が表示されるのはなぜですか?

シリアライザルーチンを変更して、UTF-16ではなくUTF-8を返す方法

返されたXMLソース:

<?xml version="1.0" encoding="utf-16"?>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <string>January</string>
  <string>February</string>
  <string>March</string>
  <string>April</string>
  <string>May</string>
  <string>June</string>
  <string>July</string>
  <string>August</string>
  <string>September</string>
  <string>October</string>
  <string>November</string>
  <string>December</string>
  <string />
</ArrayOfString>

シリアライザの呼び出し例:

DateTimeFormatInfo dateTimeFormatInfo = new DateTimeFormatInfo();
var months = dateTimeFormatInfo.MonthNames.ToList();

string SelectionId = "1234567890";

return new XmlResult<List<string>>(SelectionId)
{
    Data = months
};

シリアライザ:

public class XmlResult<T> : ActionResult
{
    private string filename = DateTime.Now.ToString("ddmmyyyyhhss");

    public T Data { private get; set; }

    public XmlResult(string selectionId = "")
    {
        if (selectionId != "")
        {
            filename = selectionId;
        }
    }

    public override void ExecuteResult(ControllerContext context)
    {
        HttpContextBase httpContextBase = context.HttpContext;
        httpContextBase.Response.Buffer = true;
        httpContextBase.Response.Clear();

        httpContextBase.Response.AddHeader("content-disposition", "attachment; filename=" + filename + ".xml");
        httpContextBase.Response.ContentType = "text/xml";

        using (StringWriter writer = new StringWriter())
        {
            XmlSerializer xml = new XmlSerializer(typeof(T));
            xml.Serialize(writer, Data);
            httpContextBase.Response.Write(writer);
        }
    }
}
15
rwkiii

応答のエンコード

私はフレームワークのこの部分に精通していません。しかし、MSDNによると、次のように HttpResponseのコンテンツエンコーディング を設定できます。

httpContextBase.Response.ContentEncoding = Encoding.UTF8;

XmlSerializerから見たエンコード

あなたの質問をもう一度読んだ後、これは難しい部分であることがわかります。問題はStringWriterの使用にあります。 .NET文字列は常にUTF-16(引用が必要^^)として保存されるため、StringWriterはこれをエンコードとして返します。したがって、XmlSerializerはXML宣言を次のように記述します。

<?xml version="1.0" encoding="utf-16"?>

これを回避するには、次のようにMemoryStreamに書き込みます。

using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8))
{
    XmlSerializer xml = new XmlSerializer(typeof(T));
    xml.Serialize(writer, Data);

    // I am not 100% sure if this can be optimized
    httpContextBase.Response.BinaryWrite(stream.ToArray());
}

その他のアプローチ

別の編集:私は気づいた this SO answer jtm001によってリンクされています。カスタムのXmlSerializerを提供するためのソリューションがXmlWriterに凝縮されています] _エンコードとしてUTF8を使用するように構成されています。

Athari proposes は、StringWriterから派生し、エンコーディングをUTF8としてアドバタイズします。

私の理解では、両方のソリューションも機能するはずです。ここでのテイクアウトは、1種類の定型コードまたは別の種類の定型コードが必要になるということです...

7

UTF8を強制するStringWriterを使用できます。これを行う1つの方法を次に示します。

public class Utf8StringWriter : StringWriter
{
    // Use UTF8 encoding but write no BOM to the wire
    public override Encoding Encoding
    {
         get { return new UTF8Encoding(false); } // in real code I'll cache this encoding.
    }
}

次に、コードでUtf8StringWriterライターを使用します。

using (StringWriter writer = new Utf8StringWriter())
{
    XmlSerializer xml = new XmlSerializer(typeof(T));
    xml.Serialize(writer, Data);
    httpContextBase.Response.Write(writer);
}

答えは 。NETでオブジェクトをUTF-8 XMLとしてシリアル化する

21
Yishai Galatzer

UTF8文字列としてシリアル化するには:

    private string Serialize(MyData data)
    {
        XmlSerializer ser = new XmlSerializer(typeof(MyData));
        // Using a MemoryStream to store the serialized string as a byte array, 
        // which is "encoding-agnostic"
        using (MemoryStream ms = new MemoryStream())
            // Few options here, but remember to use a signature that allows you to 
            // specify the encoding  
            using (XmlTextWriter tw = new XmlTextWriter(ms, Encoding.UTF8)) 
            {
                tw.Formatting = Formatting.Indented;
                ser.Serialize(tw, data);
                // Now we get the serialized data as a string in the desired encoding
                return Encoding.UTF8.GetString(ms.ToArray());
            }
    }

これをXMLとしてWeb応答で返すには、応答エンコーディングを設定することを忘れないでください。

    string xml = Serialize(data);
    Response.ContentType = "application/xml";
    Response.ContentEncoding = System.Text.Encoding.UTF8;
    Response.Output.Write(xml);
2
GBU