2009-04-23 4 views
14

Pour retourner des informations utiles dans SoapException.Detail pour un service Web asmx, j'ai pris une idée de WCF et créé une classe de panne pour contenir lesdites informations utiles. Cet objet d'erreur est ensuite sérialisé au XmlNode requis d'un SoapException levé.Sérialiser l'objet à XmlDocument

Je me demande si j'ai le meilleur code pour créer la XmlDocument - voici mon avis sur la question:

var xmlDocument = new XmlDocument(); 
var serializer = new XmlSerializer(typeof(T)); 
using (var stream = new MemoryStream()) 
{ 
    serializer.Serialize(stream, theObjectContainingUsefulInformation); 
    stream.Flush(); 
    stream.Seek(0, SeekOrigin.Begin); 

    xmlDocument.Load(stream); 
} 

Y at-il une meilleure façon de le faire?

MISE À JOUR: J'ai fini par faire ce qui suit, parce que si vous enroulez le XML dans un élément <detail> xml, vous obtenez un SoapHeaderException à la fin du client:

var serialiseToDocument = new XmlDocument(); 
var serializer = new XmlSerializer(typeof(T)); 
using (var stream = new MemoryStream()) 
{ 
    serializer.Serialize(stream, e.ExceptionContext); 
    stream.Flush(); 
    stream.Seek(0, SeekOrigin.Begin); 

    serialiseToDocument.Load(stream); 
} 

// Remove the xml declaration 
serialiseToDocument.RemoveChild(serialiseToDocument.FirstChild); 

// Memorise the node we want 
var serialisedNode = serialiseToDocument.FirstChild; 

// and wrap it in a <detail> element 
var rootNode = serialiseToDocument.CreateNode(XmlNodeType.Element, "detail", ""); 
rootNode.AppendChild(serialisedNode); 

MISE À JOUR 2: Étant donné John Saunders excellente réponse, je l'ai maintenant commencé à utiliser les éléments suivants:

private static void SerialiseFaultDetail() 
{ 
    var fault = new ServiceFault 
        { 
         Message = "Exception occurred", 
         ErrorCode = 1010 
        }; 

    // Serialise to the XML document 
    var detailDocument = new XmlDocument(); 
    var nav = detailDocument.CreateNavigator(); 

    if (nav != null) 
    { 
     using (XmlWriter writer = nav.AppendChild()) 
     { 
      var ser = new XmlSerializer(fault.GetType()); 
      ser.Serialize(writer, fault); 
     } 
    } 

    // Memorise and remove the element we want 
    XmlNode infoNode = detailDocument.FirstChild; 
    detailDocument.RemoveChild(infoNode); 

    // Move into a root <detail> element 
    var rootNode = detailDocument.AppendChild(detailDocument.CreateNode(XmlNodeType.Element, "detail", "")); 
    rootNode.AppendChild(infoNode); 

    Console.WriteLine(detailDocument.OuterXml); 
    Console.ReadKey(); 
} 
+0

J'ai mis à jour mon code postal pour l'élément de détail. –

+0

dans l'ensemble ça me semble bien, même si je pense que j'utiliserais des objets fortement typés plutôt que des vars dans ce cas. En outre, je ne sais pas que 'stream.Seak (0, SeekOrigin.Begin)' est vraiment nécessaire. – CodeMonkey1313

Répondre

18

EDIT: cRÉE SORT ut à l'intérieur de l'élément de détail

public class MyFault 
{ 
    public int ErrorCode { get; set; } 
    public string ErrorMessage { get; set; } 
} 

public static XmlDocument SerializeFault() 
{ 
    var fault = new MyFault 
        { 
         ErrorCode = 1, 
         ErrorMessage = "This is an error" 
        }; 

    var faultDocument = new XmlDocument(); 
    var nav = faultDocument.CreateNavigator(); 
    using (var writer = nav.AppendChild()) 
    { 
     var ser = new XmlSerializer(fault.GetType()); 
     ser.Serialize(writer, fault); 
    } 

    var detailDocument = new XmlDocument(); 
    var detailElement = detailDocument.CreateElement(
     "exc", 
     SoapException.DetailElementName.Name, 
     SoapException.DetailElementName.Namespace); 
    detailDocument.AppendChild(detailElement); 
    detailElement.AppendChild(
     detailDocument.ImportNode(
      faultDocument.DocumentElement, true)); 
    return detailDocument; 
} 
+0

+1 pour être une solution vraiment soignée. Cependant, étant donné que j'ai besoin d'envelopper le XML de l'objet sérialisé dans un élément racine "", quelle est la meilleure approche? J'ai essayé de créer un noeud, puis d'utiliser le navigateur du nouveau noeud, mais j'ai obtenu une exception InvalidOperationException avec "WriteStartDocument ne peut pas être appelé sur les writers créés avec ConformanceLevel.Fragment." –

+0

Ahh, maintenant je comprends. L'utilisation de la valeur de retour de ImportNode pour l'appel AppendChild était le lien dans la chaîne qui me manquait. Je déteste vraiment ces classes XML désordonnées en .net, je dois dire. Merci de votre aide. –

Questions connexes