2012-01-04 5 views
11

J'essaie de sérialiser un objet & enregistrez-le dans un champ Sql Server 2008 xml. J'ai aussi un code de désérialisation qui réhydrate l'objet. Je suis en mesure de sérialiser & enregistrer l'objet dans la base de données, mais obtenir une exception "Élément racine manquant".C# Xml Sérialisation et désérialisation

[XmlRoot("Patient")] 
public class PatientXml 
{ 
    private AddressXml _address = null; 
    private EmergencyContactXml _emergencyContact = null; 
    private PersonalXml _personal = null; 

    [XmlElement] 
    public PersonalXml Personal 
    { 
     get { return _personal; } 
     set { _personal = value; } 
    } 

    [XmlElement] 
    public AddressXml Address 
    { 
     get { return _address; } 
     set { _address = value; } 
    } 

    [XmlElement] 
    public EmergencyContactXml EmergencyContact 
    { 
     get { return _emergencyContact; } 
     set { _emergencyContact = value; } 
    } 

    public PatientXml(){} 
    public PatientXml(Patient patient) 
    { 
     _address = new AddressXml(patient.Address); 
     _emergencyContact = new EmergencyContactXml(patient.EmergencyInfo); 
     _personal = new PersonalXml(patient); 
    } 
} 

public class PersonalXml 
{ 
    private string _firstName = string.Empty, _lastName = string.Empty, _dateOfBirth = string.Empty, _phone = string.Empty; 

    [XmlAttribute] 
    public string FirstName 
    { 
     get { return _firstName; } 
     set { _firstName = value; } 
    } 

    [XmlAttribute] 
    public string LastName 
    { 
     get { return _lastName; } 
     set { _lastName = value; } 
    } 

    [XmlAttribute] 
    public string DateOfBirth 
    { 
     get { return _dateOfBirth; } 
     set { _dateOfBirth = value; } 
    } 

    [XmlAttribute] 
    public string Phone 
    { 
     get { return _phone; } 
     set { _phone = value; } 
    } 

    public PersonalXml(){} 
    public PersonalXml(Patient patient) 
    { 
     _firstName = patient.FirstName; 
     _lastName = patient.LastName; 
     _dateOfBirth = patient.DateOfBirth.ToShortDateString(); 
     _phone = patient.Phone; 
    } 
} 

public class AddressXml 
{ 
    private string _address1 = string.Empty, _address2 = string.Empty, _city = string.Empty, _state = string.Empty, _zip = string.Empty; 

    [XmlAttribute] 
    public string Address1 
    { 
     get { return _address1; } 
     set { _address1 = value; } 
    } 

    [XmlAttribute] 
    public string Address2 
    { 
     get { return _address2; } 
     set { _address2 = value; } 
    } 

    [XmlAttribute] 
    public string City 
    { 
     get { return _city; } 
     set { _city = value; } 
    } 

    [XmlAttribute] 
    public string State 
    { 
     get { return _state; } 
     set { _state = value; } 
    } 

    [XmlAttribute] 
    public string Zip 
    { 
     get { return _zip; } 
     set { _zip = value; } 
    } 

    public AddressXml(){} 
    public AddressXml(Address address) 
    { 
     _address1 = address.Address1; 
     _address2 = address.Address2; 
     _city = address.City; 
     _state = address.State; 
     _zip = address.ZipCode; 
    } 
} 

public class EmergencyContactXml 
{ 
    private string _name = string.Empty, _phone = string.Empty, _relationship = string.Empty; 

    [XmlAttribute] 
    public string Name 
    { 
     get { return _name; } 
     set { _name = value; } 
    } 

    [XmlAttribute] 
    public string Phone 
    { 
     get { return _phone; } 
     set { _phone = value; } 
    } 

    [XmlAttribute] 
    public string Relationship 
    { 
     get { return _relationship; } 
     set { _relationship = value; } 
    } 

    public EmergencyContactXml(){} 
    public EmergencyContactXml(EmergencyContact contact) 
    { 
     _name = contact.ContactName; 
     _phone = contact.Phone; 
     _relationship = contact.Relationship; 
    } 
} 

sérialisé sortie Xml:

<Patient 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Personal FirstName="Test" LastName="User 1" DateOfBirth="3/13/1966" Phone="6304449866" /> 
    <Address Address1="123 Some St" City="Bartlett" State="CT" Zip="60111" /> 
    <EmergencyContact Name="Dr Chanduwarthana" Phone="6309769484" Relationship="Father" /> 
</Patient> 

Serization & Code Désérialisation:

public static class XmlSerializer 
{ 
    public static string Serialize<T>(T item) 
    { 
     MemoryStream memStream = new MemoryStream(); 
     using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode)) 
     { 
      System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T)); 
      serializer.Serialize(textWriter, item); 

      memStream = textWriter.BaseStream as MemoryStream; 
     } 
     if (memStream != null) 
      return Encoding.Unicode.GetString(memStream.ToArray()); 
     else 
      return null; 
    } 

    public static T Deserialize<T>(string xmlString) 
    { 
     if (string.IsNullOrWhiteSpace(xmlString)) 
      return default(T); 

     using (MemoryStream memStream = new MemoryStream()) 
     { 
      using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode)) 
      { 
       memStream.Position = 0; 
       System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T)); 
       return (T)serializer.Deserialize(memStream); 
      } 
     } 
    } 
} 

Répondre

11

Dans votre code désérialisation vous créez un MemoryStream et XmlTextWriter mais vous n'êtes pas lui donner la chaîne à désérialiser.

using (MemoryStream memStream = new MemoryStream()) 
{ 
    using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode)) 
    { 
     // Omitted 
    } 
} 

Vous pouvez transmettre les octets au flux de mémoire et supprimer complètement le XmlTextWriter.

using (MemoryStream memStream = new MemoryStream(Encoding.Unicode.GetBytes(xmlString))) 
{ 
    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T)); 
    return (T)serializer.Deserialize(memStream); 
} 
+1

Cela a fonctionné !! Juste curieux ... qu'est-ce qui se passait avec le TextWriter? – Skadoosh

+2

@KP. Le XmlTextWriter n'est pas nécessaire pour la désérialisation puisque vous ne construisez aucun code XML. Dans ce cas, il a été créé avec une référence à MemoryStream et a reçu l'instruction d'utiliser Unicode mais n'a pas été référencé au-delà de sa création. J'ai également remarqué que le MemoryStream dans le code de sérialisation n'est pas éliminé. Vous devriez probablement envisager de réviser le code pour l'inclure dans un bloc using. –

0

Je crois que vous devez ajouter l'en-tête XML:

<?xml version="1.0" encoding="utf-8" ?> 

Vous coul d modifier votre méthode de sérialisation pour accepter un paramètre facultatif qui serait la cause à ajouter:

public static string Serialize<T>(T item, bool includeHeader = false) 
{ 
    MemoryStream memStream = new MemoryStream(); 
    using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode)) 
    { 
     System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T)); 
     serializer.Serialize(textWriter, item); 

     memStream = textWriter.BaseStream as MemoryStream; 
    } 
    if (memStream != null) 
     if (includeHeader) 
     { 
      return @"<?xml version=""1.0"" encoding=""utf-8"" ?>" + Environment.NewLine + Encoding.Unicode.GetString(memStream.ToArray()); 
     } 
     else 
     { 
      return Encoding.Unicode.GetString(memStream.ToArray()); 
     } 
    else 
     return null; 
} 
+0

comment je fais ça? Le code XML a été généré lorsque j'ai sérialisé l'objet. – Skadoosh

+0

Vous devriez pouvoir l'ajouter à la sortie de la méthode serialize. –

1

Il semblerait que vous une poignée sur la sérialisation XML, donc mon conseil, de stocker le fichier XML dans un champ de chaîne (varchar, nvarchar, texte, ntext) et non un domaine spécialisé.

Si vous faites ce petit interrupteur, vous serez prêt à partir ... aucune autre modification nécessaire.

Le champ XML est sujet à des validations, et plus de quelques casse-tête, et si votre application est seulement producteur et consommateur de ce champ, vous pouvez aussi prendre ce raccourci. SQL2008 (même 2005) est assez fort pour compenser les ressources que vous pourriez économiser en compilant le champ xml. Cependant, je voudrais optimiser votre code un peu, on dirait que vous avez écrit beaucoup plus de code que vous deviez. Par exemple, vous ne avez plus besoin de créer un champ privé pour stocker les données de votre propriété, par exemple:

public PersonalXml Personal 
{ 
    get { return _personal; } 
    set { _personal = value; } 
} 

fonctionnera bien si vous l'avez écrit comme:

public PersonalXml Personal { get ; set ; } 

il y a plus graisse que vous auriez pu couper ...

+0

Je pensais que le champ xml dans SQL Server 2008 est plus optimisé pour la requête XML. Ou puis-je également utiliser d'autres champs comme varchar, nvarchar, etc? – Skadoosh

Questions connexes