I have spent countless hours working on this issue, and have tried so many different things. Some background... I am working within an SSIS module using C# code to attempt to deserialize a SOAP XML stream. I have been able to deserialize XML streams before, but this one is significantly more complicated than the previous ones I have been involved with.
I have verified that the string I am using to populate my stream is correct for the results, and I am reaching the end of my rope.
Here is the method I am using to try to deserialize. You can see I have included several commented out sections to show some of the other methods I have used to try to make this work:
private Envelope GetWebServiceResultFromStream(StreamReader str)
{
bool b = true;
Envelope xmlResponse = null;
String xmlPayload = "";
//Deserialize our XML
try
{
//System.Runtime.Serialization.Formatters.Soap.SoapFormatter soapFormatter = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
//using (Stream savestream = str.BaseStream)
//{
// xmlResponse = (Envelope)soapFormatter.Deserialize(savestream);
//}
System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(Envelope));
using (Stream savestream = str.BaseStream)
{
StreamReader streamreader = new StreamReader(savestream, Encoding.UTF8);
xmlPayload = streamreader.ReadToEnd();
//xmlPayload = System.Security.SecurityElement.Escape(xmlPayload);
//xmlPayload = xmlPayload.Replace("&", "&");
//xmlPayload = xmlPayload.Replace("&", "&");
xmlPayload = xmlPayload.Replace("'", "'");
//xmlPayload = xmlPayload.Replace("soap:Envelope", "Envelope");
File.WriteAllText(#"myxml.xml",xmlPayload);
byte[] byteArray = Encoding.UTF8.GetBytes(xmlPayload);
MemoryStream secondstream = new MemoryStream(byteArray);
secondstream.Position = 0;
xmlResponse = sr.Deserialize(secondstream) as Envelope;
//xmlResponse = (Envelope)DeserializeFromXml<Envelope>(xmlPayload);
//XmlDocument doc = new XmlDocument();
//doc.Load(secondstream);
//XmlNodeReader reader = new XmlNodeReader(doc);
//using (reader)
//{
// xmlResponse = sr.Deserialize(reader) as Envelope;
//}
//System.Runtime.Serialization.Formatters.Soap.SoapFormatter soapFormatter = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
//xmlResponse = (Envelope)soapFormatter.Deserialize(secondstream);
}
//XmlDocument xmlSoapRequest = new XmlDocument();
//using (Stream savestream = str.BaseStream)
//{
// using (StreamReader readStream = new StreamReader(savestream, Encoding.UTF8))
// {
// xmlSoapRequest.Load(readStream);
// xmlPayload = xmlSoapRequest.SelectSingleNode("//Envelope/Body/GetRequisitionByDateResponse/").InnerText;
// }
//}
}
catch (Exception ex)
{
DumpException(ex);
this.ComponentMetaData.FireInformation(54, "", "Failed to deserialize: " + ex.Message + " Inner: " + ex.InnerException + " Source: " + ex.Source, "", 43, ref b);
}
return xmlResponse;
}
public static T DeserializeFromXml<T>(string xml)
{
T result;
var ser = new XmlSerializer(typeof(T));
using (var tr = new StringReader(xml))
{
result = (T)ser.Deserialize(tr);
}
return result;
}
I am using c# classes generated by feeding a response into the XML to C# converter (http://xmltocsharp.azurewebsites.net/). Unfortunately it appears the classes are too complex to put here (posts have a 30k character limit), so it has been pasted here:
http://txt.do/d91eo
I also pasted an example response:
http://txt.do/d91eb
I have consulted the wsdl and it appears that many DateTime fields are being read as strings through the converter. I am not sure if this is an issue, but I have tried to do my best to replace those data types and the error persisted.
Here is a screenshot of my error:
http://imgur.com/a/objJq
Other things I have tried:
Replacing invalid characters throughout the xml document (I found that it is doing this already, except in the case of some of the "'" characters).
Removed namespaces.
Marked all the classes as Serializable.
The Web Services object within SSIS (throws an error and doesn't let me enter any variables to send).
Regenerated the class list with a number of variants of the return result.
Found it
First add UTF8 to StreamReader : new StreamReader(FILENAME, Encoding.UTF8);
Here is your Root Class
[XmlRoot(ElementName = "Envelope", Namespace = "http://www.w3.org/2003/05/soap-envelope")]
public class Envelope
{
}
Here is you first line of XML
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
Compare Namespaces
The following code is running without exceptions. I can't include class because of size limitation. Note the namespace for Class Envelope I replaced "-" with "/". The class Envelope is constructed but all properties are null's because the namespace don't agree with the xml.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication50
{
class Program
{
static void Main(string[] args)
{
new Test();
}
}
public class Test
{
const string FILENAME = #"c:\temp\test2.xml";
public Test()
{
StreamReader reader = new StreamReader(FILENAME, Encoding.UTF8);
GetWebServiceResultFromStream(reader);
}
private Envelope GetWebServiceResultFromStream(StreamReader str)
{
bool b = true;
Envelope xmlResponse = null;
String xmlPayload = "";
//Deserialize our XML
try
{
//System.Runtime.Serialization.Formatters.Soap.SoapFormatter soapFormatter = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
//using (Stream savestream = str.BaseStream)
//{
// xmlResponse = (Envelope)soapFormatter.Deserialize(savestream);
//}
System.Xml.Serialization.XmlSerializer sr = new System.Xml.Serialization.XmlSerializer(typeof(Envelope));
using (Stream savestream = str.BaseStream)
{
StreamReader streamreader = new StreamReader(savestream, Encoding.UTF8);
xmlPayload = streamreader.ReadToEnd();
//xmlPayload = System.Security.SecurityElement.Escape(xmlPayload);
//xmlPayload = xmlPayload.Replace("&", "&");
//xmlPayload = xmlPayload.Replace("&", "&");
xmlPayload = xmlPayload.Replace("'", "'");
//xmlPayload = xmlPayload.Replace("soap:Envelope", "Envelope");
File.WriteAllText(#"myxml.xml",xmlPayload);
byte[] byteArray = Encoding.UTF8.GetBytes(xmlPayload);
MemoryStream secondstream = new MemoryStream(byteArray);
secondstream.Position = 0;
xmlResponse = sr.Deserialize(secondstream) as Envelope;
//xmlResponse = (Envelope)DeserializeFromXml<Envelope>(xmlPayload);
//XmlDocument doc = new XmlDocument();
//doc.Load(secondstream);
//XmlNodeReader reader = new XmlNodeReader(doc);
//using (reader)
//{
// xmlResponse = sr.Deserialize(reader) as Envelope;
//}
//System.Runtime.Serialization.Formatters.Soap.SoapFormatter soapFormatter = new System.Runtime.Serialization.Formatters.Soap.SoapFormatter();
//xmlResponse = (Envelope)soapFormatter.Deserialize(secondstream);
}
//XmlDocument xmlSoapRequest = new XmlDocument();
//using (Stream savestream = str.BaseStream)
//{
// using (StreamReader readStream = new StreamReader(savestream, Encoding.UTF8))
// {
// xmlSoapRequest.Load(readStream);
// xmlPayload = xmlSoapRequest.SelectSingleNode("//Envelope/Body/GetRequisitionByDateResponse/").InnerText;
// }
//}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
//DumpException(ex);
//this.ComponentMetaData.FireInformation(54, "", "Failed to deserialize: " + ex.Message + " Inner: " + ex.InnerException + " Source: " + ex.Source, "", 43, ref b);
}
return xmlResponse;
}
public static T DeserializeFromXml<T>(string xml)
{
T result;
var ser = new XmlSerializer(typeof(T));
using (var tr = new StringReader(xml))
{
result = (T)ser.Deserialize(tr);
}
return result;
}
}
[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
[XmlElement(ElementName = "Body", Namespace = "http://www.w3.org/2003/05/soap-envelope")]
public Body Body { get; set; }
[XmlAttribute(AttributeName = "soap", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Soap { get; set; }
[XmlAttribute(AttributeName = "xsi", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsi { get; set; }
[XmlAttribute(AttributeName = "xsd", Namespace = "http://www.w3.org/2000/xmlns/")]
public string Xsd { get; set; }
}
}
Related
I'm trying to serialize objects to XML. I'm having an issue that xsi and xsd are being added by default. I added the following code to remove the namespaces:
public string CommitDocumentToRepository(string extension, byte[] fileBytes)
{
//Convert to PDF
byte[] loPDFFileBytes;
ConversionService.ContentResponse loResponse = new DocumentAdapter.ConversionService.ContentResponse();
using (ConversionService.CustomPDFSoapClient loConversionServiceClient = new DocumentAdapter.ConversionService.CustomPDFSoapClient())
{
loResponse = loConversionServiceClient.OfficeToPDFContent(fileBytes, extension);
loPDFFileBytes = loResponse.ContentPDF;
}
if (loPDFFileBytes != null)
{
xform loDocContainer = new xform();
xformInstance loDocProperties = new xformInstance();
loDocProperties.FIRST_NAME= this.FirstName;
loDocProperties.LAST_NAME= this.LastName;
loDocProperties.MID_NAME = this.MidName;
loDocContainer.instance = loDocProperties;
string lsTempFile = System.IO.Path.GetTempFileName();
string lsXMLofProperties = loDocContainer.Serialize();
XmlDocument loDoc = new XmlDocument();
loDoc.LoadXml(lsXMLofProperties);
loDoc.Save(lsTempFile);
byte[] loFilePropertiesXML = Common.StreamFile(lsTempFile);
string lsReturnValue = string.Empty;
try
{
using (ISCommittalService.CommittalSoapClient loCommittalServiceClient = new DocumentAdapter.ISCommittalService.CommittalSoapClient())
{
lsReturnValue = loCommittalServiceClient.CommitDocumentByte(loPDFFileBytes, ".PDF", loFilePropertiesXML);
}
}
catch (Exception loException)
{
ADConnectionException loConnectionException = new ADConnectionException(loException);
throw loException;
}
return lsReturnValue;
}
else
return string.Empty;
}
public string Serialize()
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlWriterSettings xws = new XmlWriterSettings();
xws.OmitXmlDeclaration = true;
xws.Encoding = Encoding.UTF8;
StringBuilder loBuilder = new StringBuilder();
XmlSerializer formatter = new XmlSerializer(this.GetType());
using (StringWriter loWriter = new StringWriter(loBuilder))
{
formatter.Serialize(loWriter, this,ns);
}
return loBuilder.ToString();
}
This is the output:
<?xml version="1.0" encoding="UTF-16"?>
<xform>
<instance>
<FIRST_NAME xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance"
d3p1:type="q4:string"
xmlns:q4="http://www.w3.org/2001/XMLSchema">John</FIRST_NAME>
<MID_NAME xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance"
d3p1:type="q3:string" xmlns:q3="http://www.w3.org/2001/XMLSchema"/>
<LAST_NAME xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance"
d3p1:type="q5:string"
xmlns:q5="http://www.w3.org/2001/XMLSchema">Doe</LAST_NAME>
</instance>
</xform>
How can I remove that added xmlns (xmlns:d3p1="http://www.w3.org/2001/XMLSchema-instance"
d3p1:type="q4:string"
xmlns:q4="http://www.w3.org/2001/XMLSchema") from each object?
and how can I change it to utf-8 because xws.Encoding = Encoding.UTF8; that is my code seems doesn't have any affect.
I am trying to serialize a class in c# but the output is not quite I am after. I want to get rid of one element in output xml - class name - that comes along with serialization.
My class is:
[XmlType("ADSobjotsing")]
public class ObjKompParam
{
[XmlElement("aadressTekst")]
public string Tekst;
[XmlElement("adsOid")]
public string OID;
My code is:
protected override XElement ComposeQueryBody(object InputParams)
{
ObjKompParam param = (ObjKompParam)InputParams;
var ads_o_q = new ObjKompParam();
XElement body = new XElement(SOAPNS + "Body",
new XElement(prod + "ADSobjotsing"));
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serializer = new XmlSerializer(typeof(ObjKompParam),"");
XElement xe;
using (var stream = new MemoryStream())
{
serializer.Serialize(stream, param, ns);
stream.Position = 0;
using (XmlReader reader = XmlReader.Create(stream))
{
xe = XElement.Load(reader);
}
}
body.Descendants(prod + "ADSobjotsing").First().Add(new XElement(xe));
return body;
}
The output I get is:
<SOAP-ENV:Body>
<prod:ADSobjotsing>
<ADSobjotsing>
<aadressTekst>Sügise 10</aadressTekst>
</ADSobjotsing>
</prod:ADSobjotsing>
</SOAP-ENV:Body>
The xml output (body) I am after is following:
<SOAP-ENV:Body>
<prod:ADSobjotsing>
<aadressTekst>Sügise 10</aadressTekst>
</prod:ADSobjotsing>
</SOAP-ENV:Body>
I answer myself, as I worked out the solution:
XmlSerializer serializer = new XmlSerializer(typeof(ObjKompParam),"");
XElement xe;
using (var stream = new MemoryStream()) //write into stream
{
serializer.Serialize(stream, param, ns); //writer, object
stream.Position = 0;
using (XmlReader reader = XmlReader.Create(stream))
{
xe = XElement.Load(reader);
}
}
var child = xe.Descendants();
body.Descendants(prod + "ADSobjotsing").First().Add(child);
return body;
I made the new variable for object class ObjKompParam children and added children as descendants.
I have a Game application(WP8), where we are saving the scores of multiple attampts and showing it to user.
I have a Object with fields noOfStonesPicked and noOfFruitsPicked.
Here is my code:
MyTopic topicObj = new MyTopic ();
for (int i = 0; i <= 2; i++)
{
Test mt = new Test();
mt.noOfStonesPicked = 12;
mt.noOfFruitsPicked= 20;
topicObj.Stats.Add(mt);
}
WritetestTopicState(topicObj);
Now 3 attempts with each one having noOfStonesPicked -12 and noOfFruitsPicked - 20
Now i have saving this like :
public static void WritetestTopicState(MyTopic topic)
{
try
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
using (StreamWriter sw = new StreamWriter(store.OpenFile("12.xml", FileMode.Append, FileAccess.Write)))
{
XmlSerializer serializer = new XmlSerializer(typeof(MyTopic));
serializer.Serialize(sw, topic);
serializer = null;
}
}
}
catch (Exception)
{
throw;
}
}
Now how can i retrive these values and display ?
EDIT
This is what i have tried:
public static MyTopic ReadMockTestTopicState()
{
MyTopic topic = null;
try
{
using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication())
{
// Read application settings.
if (isoStore.FileExists("11.xml"))
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
using (StreamReader SR = new StreamReader(store.OpenFile("12.xml", FileMode.Open, FileAccess.Read)))
{
XmlSerializer serializer = new XmlSerializer(typeof(MyTopic));
topic = (MyTopic)serializer.Deserialize(SR);
serializer = null;
}
}
}
else
{
// If setting does not exists return default setting.
topic = new MyTopic();
}
}
}
catch (Exception)
{
throw;
}
return topic;
}
XmlSerializer serializer = new XmlSerializer(typeof(MyTopic));
StreamReader reader = new StreamReader(path);
_myTopic = (MyTopic)serializer.Deserialize(reader);
reader.Close();
This should be enough for deserializing, If your MyTopic object is properly serializable, I mean if properties of the MyTopic object are properly attributed for xml serialization.
Suppose I have a simple Class with just one Member a String.
public class Abc
{
private String text;
public String Text
{
get { return this.text; }
set { this.text = value; }
}
}
Now when I serialize and then deserialize it with the questionable XmlSerializer any text containing newlines ('\r\n' or Environment.NewLine) are transformed to '\n'.
How do I keep the newlines?
It is not the XmlSerializer but the XmlWriter which is removing your CR. To retain it we must have the writer convert CR to its character entity
.
XmlWriterSettings ws = new XmlWriterSettings();
ws.NewLineHandling = NewLineHandling.Entitize;
XmlSerializer ser = new XmlSerializer( typeof( Abc ) );
using (XmlWriter wr = XmlWriter.Create( "abc.xml", ws )) {
ser.Serialize( wr, s );
}
This is exactly the same with DataContractSerializer:
var ser = new DataContractSerializer( typeof( Abc ) );
using (XmlWriter wr = XmlWriter.Create( "abc.xml", ws )) {
ser.Serialize( wr, s );
}
Why do we need to do this?
This is because compliant XML parsers must, before parsing, translate CRLF and any CR not followed by a LF to a single LF. This behavior is defined in the End-of-Line handling section of the XML 1.0 specification.
As this happens before parsing, you need to encode CR as its character entity if you want the CR to exist in the document.
public class SerializeAny<TF> where TF : new()
{
public static TF Deserialize(string serializedData)
{
try
{
var xmlSerializer = new XmlSerializer(typeof(TF));
TF collection;
using (var xmlReader = new XmlTextReader(serializedData, XmlNodeType.Document, null))
{
collection = (TF)xmlSerializer.Deserialize(xmlReader);
}
return collection;
}
catch (Exception)
{
}
return new TF();
}
public static TF DeserializeZip(string path)
{
try
{
var bytes = File.ReadAllBytes(path);
string serializedData = Unzip(bytes);
TF collection = Deserialize(serializedData);
return collection;
}
catch (Exception)
{
}
return new TF();
}
public static string Serialize(TF options)
{
var xml = "";
try
{
var xmlSerializer = new XmlSerializer(typeof(TF));
using (var stringWriter = new StringWriter())
{
xmlSerializer.Serialize(stringWriter, options);
xml = stringWriter.ToString();
}
}
catch (Exception ex)
{
return ex.Message;
}
return xml;
}
public static string SerializeZip(TF options, string path)
{
var xml = "";
try
{
xml = Serialize(options);
var zip = Zip(xml);
File.WriteAllBytes(path, zip);
}
catch (Exception ex)
{
return ex.Message;
}
return xml;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
internal static String SerializeObject<T>(T obj, Encoding enc)
{
using (var ms = new MemoryStream())
{
var xmlWriterSettings = new System.Xml.XmlWriterSettings()
{
// If set to true XmlWriter would close MemoryStream automatically and using would then do double dispose
// Code analysis does not understand that. That's why there is a suppress message.
CloseOutput = false,
Encoding = enc,
OmitXmlDeclaration = false,
Indent = true
};
using (var xw = XmlWriter.Create(ms, xmlWriterSettings))
{
var s = new XmlSerializer(typeof(T));
s.Serialize(xw, obj);
}
return enc.GetString(ms.ToArray());
}
}
private static void CopyTo(Stream src, Stream dest)
{
byte[] bytes = new byte[4096];
int cnt;
while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
{
dest.Write(bytes, 0, cnt);
}
}
private static byte[] Zip(string str)
{
var bytes = Encoding.UTF8.GetBytes(str);
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream())
{
using (var gs = new GZipStream(mso, CompressionMode.Compress))
{
//msi.CopyTo(gs);
CopyTo(msi, gs);
}
return mso.ToArray();
}
}
private static string Unzip(byte[] bytes)
{
using (var msi = new MemoryStream(bytes))
using (var mso = new MemoryStream())
{
using (var gs = new GZipStream(msi, CompressionMode.Decompress))
{
CopyTo(gs, mso);
}
return Encoding.UTF8.GetString(mso.ToArray());
}
}
}
public class BinarySerialize<T> where T : new()
{
public static string Serialize(T options, string path)
{
var xml = "";
try
{
File.Delete(path);
}
catch (Exception)
{
}
try
{
using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
{
var bf = new BinaryFormatter();
bf.Serialize(fs, options);
}
}
catch (Exception ex)
{
return ex.Message;
}
return xml;
}
public static T Deserialize(string path)
{
T filteroptions;
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var bf = new BinaryFormatter();
filteroptions = (T)bf.Deserialize(fs);
}
return filteroptions;
}
}
Use this code:
public static FilterOptions Deserialize(string serializedData)
{
try
{
var xmlSerializer = new XmlSerializer(typeof(FilterOptions));
var xmlReader = new XmlTextReader(serializedData,XmlNodeType.Document,null);
var collection = (FilterOptions)xmlSerializer.Deserialize(xmlReader);
return collection;
}
catch (Exception)
{
}
return new FilterOptions();
}
Nice solution, Lachlan Roche!
The function below (in VB.NET) uses a StringWriter to return a String, rather than writing the result to a file using an XmlWriter.
''' <summary>
''' Exports the object data to an XML formatted string.
''' Maintains CR characters after deserialization.
''' The object must be serializable to work.
''' </summary>
Public Function ExportObjectXml(ByVal obj As Object) As String
If obj Is Nothing Then
Return String.Empty
End If
Dim serializer As New XmlSerializer(obj.GetType)
Dim settings As New XmlWriterSettings With {.NewLineHandling = NewLineHandling.Entitize}
Using output As New StringWriter
Using writer As XmlWriter = XmlWriter.Create(output, settings)
serializer.Serialize(writer, obj)
Return output.ToString
End Using
End Using
End Function
In order to return useful information in SoapException.Detail for an asmx web service, I took an idea from WCF and created a fault class to contain said useful information. That fault object is then serialised to the required XmlNode of a thrown SoapException.
I'm wondering whether I have the best code to create the XmlDocument - here is my take on it:
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);
}
Is there a better way of doing this?
UPDATE: I actually ended up doing the following, because unless you wrap the XML in a <detail> xml element, you get a SoapHeaderException at the client end:
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: Given John Saunders excellent answer, I've now started using the following:
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();
}
EDIT: Creates output inside of detail element
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;
}