4

0x20 未満のもの (0x09、0x0a、0x0d、つまりタブ、キャリッジ リターン、ライン フィードを除く) は、XML ドキュメントに含めることはできません。

データベースから出てくるデータがあり、Web サービス要求への応答として渡されます。

Soap フォーマッタは 0x12 文字 (Ascii 18、Device Control 2) を喜んでエンコードしますが、 16 進値 0x12のクライアントで応答が失敗し、無効な文字です。

<rant>私が非常にイライラしているのは、これらが同じコインの表裏であり、クライアントとサービスの両方が .net アプリであることです。何も読み取れない場合、soap フォーマッタが不適切な xml を書き込むのはなぜですか?</rant>

どちらかにしたい

  1. これらの奇妙な文字を正しく処理する Xml シリアライザーを取得するか、
  2. Web サービスでリクエストを失敗させる

私はグーグルで検索しましたが、a)「入力をサニタイズする」またはb)「ドキュメント構造を変更する」以外に、これについて多くを見つけることができませんでした。

a) このデータの一部は 20 年以上前のものであるため、ランナーでは
ありません。b) 独自のフロント エンド以外に、Web サービスに対して直接コーディングするクライアントがあるため、選択肢はあまりありません。

私が見逃している明らかなものはありますか?それとも単に AscII 制御コード周辺のコードのケースですか?

ありがとう

更新
これは実際には XmlSerialiser の問題です。次のコードは無効な文字をストリームにシリアル化しますが、逆シリアル化はしません。

[Serializable]
public class MyData 
{
    public string Text { get; set; }

}
class Program
{
    public static void Main(string[] args)
    {
        var myData = new MyData {Text = "hello " 
                + ASCIIEncoding.ASCII.GetString(new byte[] { 0x12 }) 
                + " world"};

        var serializer = new XmlSerializer(typeof(MyData));

        var xmlWriter = new StringWriter();

        serializer.Serialize(xmlWriter, myData);

        var xmlReader = new StringReader(xmlWriter.ToString());

        var newData = (MyData)serializer.Deserialize(xmlReader); // Exception 
        // hexadecimal value 0x12, is an invalid character.

    }
}

XmlWriter を明示的に作成し、それを に渡すことで、xml の書き込みをチョークすることができますSerialise(私自身の回答としてすぐに投稿します)。
これらの文字は重要なので、単に取り除くことはできません。送信前にエンコードし、読み取ったときにデコードする必要があります。これを行うための既存のフレームワーク メソッドがないように見えることに本当に驚いています。

4

2 に答える 2

1

2番目: 解決策

DataContractSerializer代わりに (WCF サービスの既定で使用される) を使用するとXmlSerializer、扱いがうまくいきます

[Serializable]
public class MyData
{
    public string Text { get; set; }
}
class Program
{
    public static void Main(string[] args)
    {
        var myData = new MyData
        {
            Text = "hello "
                + ASCIIEncoding.ASCII.GetString(new byte[] { 0x12 })
                + " world"
        };

        var serializer = new DataContractSerializer(typeof(MyData));

        var mem = new MemoryStream();

        serializer.WriteObject(mem, myData);

        mem.Seek(0, SeekOrigin.Begin);
        MyData myData2 = (MyData)serializer.ReadObject(mem);

        Console.WriteLine("myData2 {0}", myData2.Text);
    }
}

Frist : 回避策

XmlWriter を使用することで、Xml を書き込むときにそれを窒息させることができます。これは、クライアントが窒息するよりも間違いなく優れています。例えば

ただし、無効な文字を送信するという根本的な問題は修正されません

[Serializable]
public class MyData 
{
    public string Text { get; set; }
}
class Program
{
    public static void Main(string[] args)
    {
        var myData = new MyData {Text = "hello " 
            + ASCIIEncoding.ASCII.GetString(new byte[] { 0x12 }) 
            + " world"};
        var serializer = new System.Xml.Serialization.XmlSerializer(typeof(MyData));

        var sw = new StringWriter();
        XmlWriterSettings settings = new XmlWriterSettings();

        using (var writer = XmlWriter.Create(sw))
        {
            serializer.Serialize(writer, myData); // Exception
            // hexadecimal value 0x12, is an invalid character
        }
        var xmlReader = new StringReader(sw.ToString());

        var newUser = (MyData)serializer.Deserialize(xmlReader);

        Console.WriteLine("User Name = {0}", newUser);

    }
}
于 2011-11-22T10:04:40.160 に答える
0

Binary Worrier の投稿と挿入された特殊文字フィルターの組み合わせは、オブジェクトが返される直前にフィルター処理するのに非常にうまく機能します。

public List<MyData> MyWebServiceMethod()
{
    var mydata = GetMyData();
    return Helper.ScrubObjectOfSpecialCharacters<List<MyData>>(mydata);
}

ヘルパー クラス:

public static T ScrubObjectOfSpecialCharacters<T>(T obj)
{
    var serializer = new XmlSerializer(obj.GetType());

    using (StringWriter writer = new StringWriter())
    {
        serializer.Serialize(writer, obj);

        string content = writer.ToString();

        content = FixSpecialCharacters(content);

        using (StringReader reader = new StringReader(content))
        {
            obj = (T)serializer.Deserialize(reader);
        }
    }
    return obj;
}
public static string FixSpecialCharacters(string input)
{
    if (string.IsNullOrEmpty(input)) return input;

    StringBuilder output = new StringBuilder();
    for (int i = 0; i < input.Length; i++)
    {
        int charCode = (int)input[i];
        switch (charCode)
        {
            case 8211:
            case 8212:
                {
                    // replaces short and long hyphen
                    output.Append('-');
                    break;
                }
            default:
                {
                    if ((31 < charCode && charCode < 127) || charCode == 9)
                    {
                        output.Append(input[i]);
                    }
                    break;
                }
        }
    }
    return output.ToString();
}
于 2012-09-13T20:40:31.737 に答える