2009-04-23 13 views
14

W celu zwrócenia użytecznych informacji w SoapException.Detail dla usługi sieciowej ASMX, wziąłem pomysł z WCF i utworzyłem klasę błędów, aby zawrzeć te użyteczne informacje. Ten obiekt błędu jest następnie serializowany do wymaganego XmlNode wyrzuconego SoapException.Serialize object to XmlDocument

Zastanawiam się czy mam najlepszą kod w celu utworzenia XmlDocument - tu jest moje zdanie na jej temat:

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

Czy istnieje lepszy sposób to zrobić?

UPDATE: I rzeczywiście skończyło się wykonaniem poniższego, bo chyba owijać XML w elemencie <detail> xml, masz SoapHeaderException na końcu klient:

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

UPDATE 2: Zważywszy John Saunders doskonała odpowiedź, mam teraz zaczął używać następujące:

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

Zaktualizowałem swój kod pocztowy dla elementu szczegółów. –

+0

ogólnie rzecz biorąc wygląda mi to dobrze, choć wydaje mi się, że w tym przypadku użyłbym raczej obiektów wpisanych na maszynie, a nie vars. Ponadto, nie wiem, że 'stream.Seak (0, SeekOrigin.Begin) jest naprawdę konieczne. – CodeMonkey1313

Odpowiedz

18

EDIT: Tworzy outp ut wewnątrz elementu szczegółów

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 za bycie naprawdę schludnym rozwiązaniem. Jednakże, biorąc pod uwagę, że muszę zawinąć XML serializowanego obiektu do głównego elementu "", jakie jest najlepsze podejście? Próbowałem utworzyć węzeł, a następnie użyć nawigatora nowego węzła, ale otrzymałem wyjątek InvalidOperationException z "WriteStartDocument nie można wywołać na pisarzach utworzonych za pomocą ConformanceLevel.Fragment". –

+0

Ahh, teraz rozumiem. Użycie zwracanej wartości funkcji ImportNode dla wywołania AppendChild było linkiem w łańcuchu, którego ja brakowało. Naprawdę nienawidzę tych niechlujnych klas XML w .net, muszę przyznać. Dzięki za pomoc. –