2012-06-27 68 views
7

我正在构建一个自托管的WCF服务。我正在构建一个非常灵活的数据传输的特殊数据结构。到目前为止,我测试了我的结构是否可以使用DataContractSerializer进行序列化。这工作得很好,我感到高兴,但也有一些是讨厌我:为DataContractSerializer预定义XML名称空间

在我的XML输出几十重新定义的xmlns属性,如:

xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" 
xmlns:b="http://www.w3.org/2001/XMLSchema" 

这应该在根元素可以更好地定义一次所以可以简单地优化字节。有没有办法将自定义命名空间信息添加到根元素?

这是一个更大的例子来说明我的意思:

<DataObject xmlns="http://schemas.datacontract.org/2004/07/Test" 
      xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 
    <Data xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"> 
    <a:KeyValueOfstringanyType> 
     <a:Key>ID</a:Key> 
     <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">1</a:Value> 
    </a:KeyValueOfstringanyType> 
    <a:KeyValueOfstringanyType> 
     <a:Key>Value</a:Key> 
     <a:Value i:type="b:int" xmlns:b="http://www.w3.org/2001/XMLSchema">42</a:Value> 
    </a:KeyValueOfstringanyType> 
    </Data> 
    <Data xmlns:a="...">...</Data> 
    <Data xmlns:a="...">...</Data> 
    <Data xmlns:a="...">...</Data> 
</DataObject> 

我想是这样的:

<DataObject xmlns="http://schemas.datacontract.org/2004/07/Test" 
      xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
      xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays" 
      xmlns:b="http://www.w3.org/2001/XMLSchema"> 
    <Data> 
    <a:KeyValueOfstringanyType> 
     <a:Key>ID</a:Key> 
     <a:Value i:type="b:int">1</a:Value> 
    </a:KeyValueOfstringanyType> 
    <a:KeyValueOfstringanyType> 
     <a:Key>Value</a:Key> 
     <a:Value i:type="b:int">42</a:Value> 
    </a:KeyValueOfstringanyType> 
    </Data> 
    <Data>...</Data> 
    <Data>...</Data> 
    <Data>...</Data> 
</DataObject> 
+0

(HTTP [如何序列化对象到XML没有得到的xmlns =“...”?]:/ /stackoverflow.com/questions/258960/how-to-serialize-an-object-to-xml-without-getting-xmlns)< - 这包含你想要的 –

+0

@MarkusJarderot没有不是真的。这似乎是一种摆脱通用名称空间的方式。 WCF合同需要(到目前为止我知道)!我只是想避免有严重的重新定义。 – rekire

回答

12
static void Main() 
{ 
    var o = new Foo { 
     Prop = new Dictionary<string,string> { {"foo","bar"} } 
    }; 

    var ms = new MemoryStream(); 

    var slz = new DataContractSerializer(typeof(Foo)); 
    slz.WriteObject(ms, o, 
     new Dictionary<string,string> 
     { 
      { "arr", "http://schemas.microsoft.com/2003/10/Serialization/Arrays" }, 
     }); 

    string data = Encoding.UTF8.GetString(ms.ToArray()); 
    Console.WriteLine(data); 
} 

public static class Extensions 
{ 
    public static void WriteObject(
     this DataContractSerializer serializer, 
     Stream stream, object data, 
     Dictionary<string,string> namespaces) 
    { 
     using (var writer = XmlWriter.Create(stream)) 
     { 
      serializer.WriteStartObject(writer, data); 
      foreach (var pair in namespaces) 
      { 
       writer.WriteAttributeString("xmlns", pair.Key, null, pair.Value); 
      } 
      serializer.WriteObjectContent(writer, data); 
      serializer.WriteEndObject(writer); 
     } 
    } 
} 

[DataContract] 
class Foo 
{ 
    [DataMember] 
    public Dictionary<string,string> Prop; 
} 

输出:

<?xml version="1.0" encoding="utf-8"?> 
<Foo xmlns:arr="http://schemas.microsoft.com/2003/10/Serialization/Arrays" 
    xmlns:i="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://schemas.datacontract.org/2004/07/"> 
    <Prop> 
     <arr:KeyValueOfstringstring> 
      <arr:Key>foo</arr:Key> 
      <arr:Value>bar</arr:Value> 
     </arr:KeyValueOfstringstring> 
    </Prop> 
</Foo> 
+0

看起来很完美。只是可惜没有为我添加声明的属性。 – rekire

+0

@rekire你可能想看看http://stackoverflow.com/a/6574024/22364 –

+0

这似乎是一个合适的解决方案。再次感谢你!使用'DataContractSerializer'工作一切正常。但'DataContractJsonSerializer'抛出一个SerializationException提到'DataContractResolver'或我应该使用'KnownTypeAttribute'。为什么'DataContractJsonSerializer'想要这个,但DataContractSerializer'不是? – rekire

2

我成功使用这里描述的解决方案:http://blogs.msdn.com/b/youssefm/archive/2009/07/24/optimizing-away-repeat-xml-namespace-declarations-with-datacontractserializer.aspx

您基本上会创建一个行为,为您添加名称空间到根元素。

从文章:

只需创建一个从XmlObjectSerializer继承使用的DataContractSerializer为它的所有方法,不同的是它注册在顶层附加命名空间的事实串行。然后用CreateSerializer方法创建一个从DataContractSerializerOperationBehavior派生的行为,该方法返回刚创建的XmlObjectSerializer并插入行为。

如果你想这样做在Silverlight中,你也可以使用这里描述的解决方案:http://blogs.msdn.com/b/carlosfigueira/archive/2011/05/24/wcf-extensibility-custom-serialization-in-silverlight.aspx