2009-04-23 20 views
14

Para devolver información útil en SoapException.Detail para un servicio web de asmx, tomé una idea de WCF y creé una clase de falla para contener dicha información útil. Ese objeto de falla se serializa al requerido XmlNode de un SoapException arrojado.Serializar el objeto a XmlDocument

Me pregunto si tengo el mejor código para crear el XmlDocument - aquí está mi opinión sobre ella:

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

¿Hay una mejor manera de hacer esto?

ACTUALIZACIÓN: verdad es que acabé haciendo lo siguiente, porque a menos que se coloca el código XML en un elemento de <detail> xml, se obtiene una SoapHeaderException en el extremo del cliente:

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

ACTUALIZACIÓN 2: Dado John Saunders excelente respuesta, ahora que he empezado a utilizar el siguiente:

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

He actualizado mi código postal para el elemento de detalle. –

+0

en general, se ve bien para mí, aunque creo que usaría objetos fuertemente tipados en lugar de vars en este caso. Además, no sé que 'stream.Seak (0, SeekOrigin.Begin)' es realmente necesario. – CodeMonkey1313

Respuesta

18

EDIT: crea outp ut dentro del elemento de detalle

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 por ser una solución realmente ordenada. Sin embargo, dado que necesito envolver el XML del objeto serializado en un elemento raíz "", ¿cuál es el mejor enfoque? Intenté crear un nodo y luego usar el navegador del nuevo nodo, pero obtuve una InvalidOperationException con "WriteStartDocument no se puede invocar a los escritores creados con ConformanceLevel.Fragment". –

+0

Ahh, ahora lo entiendo. Usar el valor de retorno de ImportNode para la llamada AppendChild fue el enlace en la cadena que me faltaba. Realmente odio estas desordenadas clases XML en .net, debo decir. Gracias por tu ayuda. –

Cuestiones relacionadas