派生 class 的 DataContractSerializer 命名空间与属性中指定的不匹配
DataContractSerializer namespace for derived class does not match specified in attribute
我期望 XML 输出如下:
<MyBase type="MyDerived"
xmlns="http://www.mynamespace.com/MySchema" />
相反,我的实际输出如下:
<MyBase i:type="MyDerived"
xmlns="http://www.mynamespace.com/MySchema"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
我正在使用以下 class 定义来尝试生成我预期的输出:
MyBase.cs
namespace MyProject
{
[KnownType(typeof(MyDerived))]
[DataContract(Namespace = MyBase.Namespace)]
public abstract class MyBase
{
public const string Namespace = "http://www.mynamespace.com/MySchema";
}
}
MyDerived.cs
namespace MyProject.Events
{
[DataContract(Namespace = MyBase.Namespace)]
public sealed class MyDerived : MyBase {}
}
我正在使用以下序列化代码:
var knownTypes = new Type[]
{
typeof(MyDerived)
};
var xmlDictionary = new XmlDictionary(1);
var settings = new DataContractSerializerSettings();
settings.KnownTypes = knownTypes;
settings.RootNamespace = xmlDictionary.Add(MyBase.Namespace);
serializer = new DataContractSerializer(typeof(MyBase), settings);
var actual = String.Empty;
using (var memoryStream = new MemoryStream())
{
serializer.WriteObject(memoryStream, new MyDerived());
memoryStream.Position = 0;
using (var streamReader = new StreamReader(memoryStream))
{
actual = streamReader.ReadToEnd();
}
}
我不确定为什么它对我的派生对象使用 XMLSchema-instance
命名空间而不是我指定使用的命名空间。我花了一个多小时在 Whosebug、Google 和 MSDN 上挖掘,试图找出我做错了什么,但我一定是错过了它。看起来很接近,这一定是一个简单的错误。
这是我的 class 结构的问题,还是我以某种方式误用了属性?
如何获得预期的输出?
您可能只是误读了 XML 并且一切正常。在您的 XML 中,命名空间 xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
仅用于限定 属性 i:type
,除此之外别无其他。您的所有实际数据都在您指定的命名空间中。如果对象本身位于不同的命名空间中,您会看到类似以下内容:
i:type="i:MyDerived"
但你不是。
http://www.w3.org/2001/XMLSchema-instance
is a W3C globally standard namespace, knowledge of which is built in to DataContractSerializer
(as well as many other XML serializers). It contains 4 built-in attributes defined as follows in the standards document:
nil
:如果一个元素具有值为 true
.
[=59= 的元素,则表明该元素在没有内容的情况下可能是·有效·的]
schemaLocation
和 noNamespaceSchemaLocation
:用于提供有关架构文档物理位置的提示。
type
:实例中的元素信息项可以使用属性 type
显式断言其类型。该属性的值为·QName·。
您看到的 i:type
是这些全球公认的标准属性中的最后一个。它说:"this element has the following type"。 DataContractSerializer
使用它来表示 .Net 类型信息的原因可能包括:
是标准的。例如XmlSerializer
recognizes and supports the same attribute.
您的元素可能有自己的名为 type
的数据属性。如果是这样,它将驻留在自己的命名空间中,not http://www.w3.org/2001/XMLSchema-instance
。后者是为架构信息而不是内容保留的约定,从而避免了名称冲突。
有关更多信息,请参阅 Understanding Known Types and Data Contract Known Types。
不幸的是,即使使用自定义 XmlWriter
,您也无法实现它。 DataContractSerializer
不像 XMLSerializer
那样工作。添加到您的 xml 中的信息是为了支持以下事实:
The line xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" tells the XML parser that this document should be validated against a schema.
这些命名空间也被视为保留命名空间。因此,如果您尝试覆盖它们,.Net 运行时将抛出异常。
@dbc 解释得很好,包含命名空间是一个非常标准的过程的一部分,对您的 xml.
无害
如果你真的需要摆脱这个默认的命名空间,那么你只需要 hack 你的 XML 输出与字符串替换方法。但这可能会导致您在脱盐时遇到问题。
我期望 XML 输出如下:
<MyBase type="MyDerived"
xmlns="http://www.mynamespace.com/MySchema" />
相反,我的实际输出如下:
<MyBase i:type="MyDerived"
xmlns="http://www.mynamespace.com/MySchema"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" />
我正在使用以下 class 定义来尝试生成我预期的输出:
MyBase.cs
namespace MyProject
{
[KnownType(typeof(MyDerived))]
[DataContract(Namespace = MyBase.Namespace)]
public abstract class MyBase
{
public const string Namespace = "http://www.mynamespace.com/MySchema";
}
}
MyDerived.cs
namespace MyProject.Events
{
[DataContract(Namespace = MyBase.Namespace)]
public sealed class MyDerived : MyBase {}
}
我正在使用以下序列化代码:
var knownTypes = new Type[]
{
typeof(MyDerived)
};
var xmlDictionary = new XmlDictionary(1);
var settings = new DataContractSerializerSettings();
settings.KnownTypes = knownTypes;
settings.RootNamespace = xmlDictionary.Add(MyBase.Namespace);
serializer = new DataContractSerializer(typeof(MyBase), settings);
var actual = String.Empty;
using (var memoryStream = new MemoryStream())
{
serializer.WriteObject(memoryStream, new MyDerived());
memoryStream.Position = 0;
using (var streamReader = new StreamReader(memoryStream))
{
actual = streamReader.ReadToEnd();
}
}
我不确定为什么它对我的派生对象使用 XMLSchema-instance
命名空间而不是我指定使用的命名空间。我花了一个多小时在 Whosebug、Google 和 MSDN 上挖掘,试图找出我做错了什么,但我一定是错过了它。看起来很接近,这一定是一个简单的错误。
这是我的 class 结构的问题,还是我以某种方式误用了属性?
如何获得预期的输出?
您可能只是误读了 XML 并且一切正常。在您的 XML 中,命名空间 xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
仅用于限定 属性 i:type
,除此之外别无其他。您的所有实际数据都在您指定的命名空间中。如果对象本身位于不同的命名空间中,您会看到类似以下内容:
i:type="i:MyDerived"
但你不是。
http://www.w3.org/2001/XMLSchema-instance
is a W3C globally standard namespace, knowledge of which is built in to DataContractSerializer
(as well as many other XML serializers). It contains 4 built-in attributes defined as follows in the standards document:
[=59= 的元素,则表明该元素在没有内容的情况下可能是·有效·的]nil
:如果一个元素具有值为true
.schemaLocation
和noNamespaceSchemaLocation
:用于提供有关架构文档物理位置的提示。type
:实例中的元素信息项可以使用属性type
显式断言其类型。该属性的值为·QName·。
您看到的 i:type
是这些全球公认的标准属性中的最后一个。它说:"this element has the following type"。 DataContractSerializer
使用它来表示 .Net 类型信息的原因可能包括:
是标准的。例如
XmlSerializer
recognizes and supports the same attribute.您的元素可能有自己的名为
type
的数据属性。如果是这样,它将驻留在自己的命名空间中,nothttp://www.w3.org/2001/XMLSchema-instance
。后者是为架构信息而不是内容保留的约定,从而避免了名称冲突。
有关更多信息,请参阅 Understanding Known Types and Data Contract Known Types。
不幸的是,即使使用自定义 XmlWriter
,您也无法实现它。 DataContractSerializer
不像 XMLSerializer
那样工作。添加到您的 xml 中的信息是为了支持以下事实:
The line xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" tells the XML parser that this document should be validated against a schema.
这些命名空间也被视为保留命名空间。因此,如果您尝试覆盖它们,.Net 运行时将抛出异常。
@dbc 解释得很好,包含命名空间是一个非常标准的过程的一部分,对您的 xml.
无害如果你真的需要摆脱这个默认的命名空间,那么你只需要 hack 你的 XML 输出与字符串替换方法。但这可能会导致您在脱盐时遇到问题。