2012-06-27 21 views
7

Sto costruendo un servizio WCF autoportante. Sto costruendo una struttura dati speciale per un trasporto dei dati molto flessibile. Finora provo se la mia struttura è serializzabile usando DataContractSerializer. Che funziona bene e sono felice di questo, ma c'è qualcosa di fastidioso me:Predefinire gli spazi dei nomi XML per DataContractSerializer

Nel mio output XML sono decine ridefiniti xmlns attributi ad esempio:

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

Questo dovrebbe essere meglio definito una volta l'elemento radice in modo che i byte possano essere semplicemente ottimizzati. C'è un modo per aggiungere informazioni di namespace personalizzate all'elemento root?

Ecco un esempio più grande di dimostrare quello che voglio dire:

<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> 

Quello che voglio è qualcosa di simile:

<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 [Come serializzare un oggetto in XML senza ottenere xmlns = “...”?]://stackoverflow.com/questions/258960/how-to-serialize-an-object-to-xml-without-getting-xmlns) <- Questo contiene ciò che vuoi –

+0

@MarkusJarderot no non proprio. Sembra essere un modo per sbarazzarsi degli spazi dei nomi in generale. I contratti di WCF hanno bisogno di quello (finora lo so)! Voglio solo evitare che ci siano ridefinizioni severe. – rekire

risposta

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; 
} 

uscita:

<?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

Sembra perfetto. Peccato solo che non ci sia attributo che aggiunge quella declinazione per me. – rekire

+0

@rekire Si potrebbe voler guardare http://stackoverflow.com/a/6574024/22364 –

+0

Questa sembra essere una soluzione adeguata. Grazie ancora! Con 'DataContractSerializer' funziona tutto bene. Ma 'DataContractJsonSerializer' lancia una SerializationException che parla di' DataContractResolver' o che dovrei usare 'KnownTypeAttribute'. Perché 'DataContractJsonSerializer' lo vuole, ma non' DataContractSerializer'? – rekire

2

I utilizzato con successo la soluzione descritta qui : http://blogs.msdn.com/b/youssefm/archive/2009/07/24/optimizing-away-repeat-xml-namespace-declarations-with-datacontractserializer.aspx

Fondamentalmente si crea un comportamento che aggiunge gli spazi dei nomi all'elemento radice.

Dall'articolo:

Basta creare un serializzatore che eredita da XmlObjectSerializer che utilizza un DataContractSerializer per tutti i suoi metodi, tranne che per il fatto che si registra spazi dei nomi supplementari a livello superiore. Quindi creare un comportamento che deriva da DataContractSerializerOperationBehavior con un metodo CreateSerializer che restituisce il XmlObjectSerializer appena creato e collegare il comportamento.

Nel caso in cui si vuole fare in Silverlight, è anche possibile utilizzare la soluzione descritta qui: http://blogs.msdn.com/b/carlosfigueira/archive/2011/05/24/wcf-extensibility-custom-serialization-in-silverlight.aspx

Problemi correlati