我拥有一个通过“添加服务引用…”操作生成的对象,我正在使用自己编写的通用序列化程序手动对其进行序列化。
我的问题是数据合同中包含一些内部对象。
序列化程序会在内部对象的起始标签上添加一个空命名空间属性。是否有办法阻止它发生?
xmlns
声明就是正确的方式。您可以使用[assembly: ContractNamespace]
属性来覆盖程序集中所有合同的命名空间。请参考数据合同名称中的示例。
编辑:以下是一些示例的详细说明。
假设您正在手动构建一个XML文档,并且没有为任何元素指定命名空间。
XDocument xmlDocument = new XDocument(
new XElement("Book",
new XElement("Title", "Animal Farm"),
new XElement("Author", "George Orwell"),
new XElement("Publisher",
new XElement("Name", "Secker and Warburg"),
new XElement("Location", "London"),
new XElement("Founded", 1910))));
return xmlDocument.ToString();
<Book>
<Title>Animal Farm</Title>
<Author>George Orwell</Author>
<Publisher>
<Name>Secker and Warburg</Name>
<Location>London</Location>
<Founded>1910</Founded>
</Publisher>
</Book>
如果您为根元素指定了一个命名空间,那么所有子元素必须明确地退出该默认命名空间,使用xml = ""
声明。 根据命名空间默认规则:
默认命名空间声明的范围从其出现在的开始标记到相应的结束标记的末尾,不包括任何内部默认命名空间声明的范围。 对于空标签,范围是标记本身。
因此,针对根元素指定命名空间的以下代码...
XDocument xmlDocument = new XDocument(
new XElement("{http://example.com/library}Book",
new XElement("Title", "Animal Farm"),
new XElement("Author", "George Orwell"),
new XElement("Publisher",
new XElement("Name", "Secker and Warburg"),
new XElement("Location", "London"),
new XElement("Founded", 1910))));
return xmlDocument.ToString();
...将生成以下XML:
<Book xmlns="http://example.com/library">
<Title xmlns="">Animal Farm</Title>
<Author xmlns="">George Orwell</Author>
<Publisher xmlns="">
<Name>Secker and Warburg</Name>
<Location>London</Location>
<Founded>1910</Founded>
</Publisher>
</Book>
<Publisher>
元素的子元素不需要退出根命名空间,因为它们从其父级继承“无命名空间”声明。xmlns=""
声明,在演示的目的下,我们可以将相同的命名空间分配给所有后代。XDocument xmlDocument = new XDocument(
new XElement("{http://example.com/library}Book",
new XElement("{http://example.com/library}Title", "Animal Farm"),
new XElement("{http://example.com/library}Author", "George Orwell"),
new XElement("{http://example.com/library}Publisher",
new XElement("{http://example.com/library}Name", "Secker and Warburg"),
new XElement("{http://example.com/library}Location", "London"),
new XElement("{http://example.com/library}Founded", 1910))));
return xmlDocument.ToString();
<Book xmlns="http://example.com/library">
<Title>Animal Farm</Title>
<Author>George Orwell</Author>
<Publisher>
<Name>Secker and Warburg</Name>
<Location>London</Location>
<Founded>1910</Founded>
</Publisher>
</Book>
[DataContract]
public class Book
{
[DataMember]
public string Title { get; set; }
[DataMember]
public string Author { get; set; }
[DataMember]
public Publisher Publisher { get; set; }
}
[DataContract]
public class Publisher
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Location { get; set; }
[DataMember]
public short Founded { get; set; }
}
[ServiceContract]
public interface ILibraryService
{
[OperationContract]
Book GetBook();
}
public class LibraryService : ILibraryService
{
public Book GetBook()
{
return new Book
{
Title = "Animal Farm",
Author = "George Orwell",
Publisher = new Publisher
{
Name = "Secker and Warburg",
Location = "London",
Founded = 1910,
}
};
}
}
Books
元素中:using (var libraryClient = new LibraryServiceReference.LibraryServiceClient())
{
var book = libraryClient.GetBook();
var stringBuilder = new StringBuilder();
using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder))
{
xmlWriter.WriteStartElement("Books", "http://example.com/library");
var serializer = new XmlSerializer(book.GetType());
serializer.Serialize(xmlWriter, book);
xmlWriter.WriteEndElement();
}
return stringBuilder.ToString();
}
Book
包含一个xmlns=""
声明。<?xml version="1.0" encoding="utf-16"?>
<Books xmlns="http://example.com/library">
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="">
<ExtensionData />
<Author>George Orwell</Author>
<Publisher>
<ExtensionData />
<Founded>1910</Founded>
<Location>London</Location>
<Name>Secker and Warburg</Name>
</Publisher>
<Title>Animal Farm</Title>
</Book>
</Books>
如上所述,可以通过将Book
元素(以及其后代)的命名空间设置为与根元素相对应来消除xmlns=""
。对于XmlSerializer
类,所有元素的默认命名空间可以通过其构造函数的第二个参数指定。(实际技术会因使用的序列化策略而异。)
using (var libraryClient = new LibraryServiceReference.LibraryServiceClient())
{
var book = libraryClient.GetBook();
var stringBuilder = new StringBuilder();
using (XmlWriter xmlWriter = XmlWriter.Create(stringBuilder))
{
xmlWriter.WriteStartElement("Books", "http://example.com/library");
var serializer = new XmlSerializer(book.GetType(), "http://example.com/library");
serializer.Serialize(xmlWriter, book);
xmlWriter.WriteEndElement();
}
return stringBuilder.ToString();
}
这将会得到预期的结果:
<?xml version="1.0" encoding="utf-16"?>
<Books xmlns="http://example.com/library">
<Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ExtensionData />
<Author>George Orwell</Author>
<Publisher>
<ExtensionData />
<Founded>1910</Founded>
<Location>London</Location>
<Name>Secker and Warburg</Name>
</Publisher>
<Title>Animal Farm</Title>
</Book>
</Books>
DataContractSerializer
,但我(错误地)假设服务本身为其数据契约声明了空的(或不正确的)命名空间(例如 [DataContract(Namespace="")]
),这在客户端使用该序列化程序绕过是不容易的。XmlSerializer
忽略在数据契约上声明的命名空间,允许您替换自己的命名空间。无论如何,很高兴您找到了一个简单的解决方案! - Douglas[DataContract]
,则可能不适用。而这适用于从 WSDL 生成的代理代码(在与 Java 终结点的互操作环境中,我们被告知 xmlns="" 是无效的)。因此,我在这里提供这个信息以帮助您。XmlElementAttribute.Form
属性设置为 System.Xml.Schema.XmlSchemaForm.Unqualified
时,WCF 请求中的子成员可能会输出 xmlns=""。[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
public string MyProperty {
get; set;
}
<MyObject xmlns="http://some.namespance">
<MyProperty xmlns="">My value goes here</MyProperty>
</MyObject>
System.Xml.Schema.XmlSchemaForm.None
(默认值)意味着它不会输出“未限定的”命名空间属性。[System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.None)]
public string MyProperty {
get; set;
}
这会生成以下内容:
<MyObject xmlns="http://some.namespance">
<MyProperty>My value goes here</MyProperty>
</MyObject>
我不确定在导入wsdl引用时是否可以更改此行为,或者可能应该更改wsdl,但最终我直接编辑了生成的代理代码(这绝对不是理想的方法),但实现了我的即时目标。
var serializer = new XmlSerializer(target.GetType());
var ns = new XmlSerializerNamespaces();
ns.Add("","");
serializer.Serialize(xmlWriter, target, ns);
此致敬礼,
xmlns=""
是正确的。 - John Saunders