4

任何低于 0x20 的内容(除了 0x09、0x0a、0x0d 即制表符、回车符和换行符)都不能包含在 XML 文档中。

我有一些来自数据库的数据并作为对 Web 服务请求的响应被传递。

Soap 格式化程序愉快地编码 0x12 字符(Ascii 18,设备控制 2),但客户端上的响应失败,十六进制值 0x12,是无效字符

<rant>我觉得非常令人沮丧的是,这是同一枚硬币的两个方面,客户端和服务都是 .net 应用程序。如果没有东西可以读取,为什么肥皂格式化程序会写坏 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 并将其传递给它来阻止写入Serialisexml (我将尽快将其发布为我自己的答案),但这仍然意味着我必须在发送数据之前对其进行清理。
由于这些字符很重要,我不能只是剥离它们,我需要在传输之前对它们进行编码,并在读取它们时对其进行解码,我真的很惊讶似乎没有现有的框架方法可以做到这一点。

4

2 回答 2

1

第二:一个解决方案

使用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);
    }
}

第一:一种解决方法

通过使用 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 回答