Code Reference A collection of code for my reference (and perhaps other people too)

8Mar/100

Serialization to XML with CDATA tags

Sometimes you need CDATA tags around complex text in your destination XML.

There is no build in way of doing so (that I have found).

I found this nifty CdataWrapper class on Marc Gravell's blog. Thanks Marc!

Here is the basic class.

public sealed class CDataWrapper : IXmlSerializable
{
        // implicit to/from string
        public static implicit operator string(CDataWrapper value)
        {
            return value == null ? null : value.Value;
        }
        public static implicit operator CDataWrapper(string value)
        {
            return value == null ? null : new CDataWrapper
            {
                Value =
                    value
            };
        }
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }
        // "" => <Node/>
        // "Foo" => <Node><![CDATA[Foo]]></Node>
        public void WriteXml(XmlWriter writer)
        {
            if (!string.IsNullOrEmpty(Value))
            {
                writer.WriteCData(Value);
            }
        }
        // <Node/> => ""
        // <Node></Node> => ""
        // <Node>Foo</Node> => "Foo"
        // <Node><![CDATA[Foo]]></Node> => "Foo"
        public void ReadXml(XmlReader reader)
        {
            if (reader.IsEmptyElement)
            {
                Value = "";
            }
            else
            {
                reader.Read();
                switch (reader.NodeType)
                {
                    case XmlNodeType.EndElement:
                        Value = ""; // empty after all...
                        break;
                    case XmlNodeType.Text:
                    case XmlNodeType.CDATA:
                        Value = reader.ReadContentAsString();
                        break;
                    default:
                        throw new InvalidOperationException("Expected text/cdata");
                }
            }
        }
        // underlying value
        public string Value { get; set; }
        public override string ToString()
        {
            return Value;
        }
}

To use it, you must change your DataMember from String to CDataWrapper, make it private and give it a public property.

This:

[DataMember]
pubblic string Answer { get; set; }

Becomes this:

pubblic string Answer { get; set; }
[DataMember(Name="Answer", EmitDefaultValue=false)]
private CDataWrapper AnswerCDATA
{
    get { return Answer; }
    set { Answer = value; }
}

Then the serialization is done with one line:

.
.
.
XElement xml = Microsoft.ServiceModel.Web.SerializationExtensions.ToXml(object);
.

So simple!!!!

8Mar/100

More on Object Serialization to XML

It seems there are hundreds of ways to serialize object.

Here are just a few:

This one now seems very clumbsy. You pass in the object and the object type. It returns a string. I can't see the point of using this one any more now that I have found the next one.

public static string ContractObjectToXml<T>(T obj)
{
    DataContractSerializer dataContractSerializer = new DataContractSerializer(obj.GetType());
    String text;
    using (MemoryStream memoryStream = new MemoryStream())
    {
        dataContractSerializer.WriteObject(memoryStream, obj);
        byte[] data = new byte[memoryStream.Length];
        Array.Copy(memoryStream.GetBuffer(), data, data.Length);
        text = Encoding.UTF8.GetString(data);
    }
    return text;
}

This one I have started using is the most simple I have seen so far.

.
.
.
XElement xml = Microsoft.ServiceModel.Web.SerializationExtensions.ToXml(object);
.

This one returns a stream. It gives you a bit more control over what is shown and included in the XML.

public static Stream Serialize(Object obj)
{
            MemoryStream memoryStream = new MemoryStream();
            DataContractSerializer dcSerializer = new DataContractSerializer(obj.GetType());
            XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
            xmlWriterSettings.Encoding = new UTF8Encoding(false);
            xmlWriterSettings.ConformanceLevel = ConformanceLevel.Document;
            xmlWriterSettings.Indent = true;
            //xmlWriterSettings.OmitXmlDeclaration = true;

            using (XmlWriter xWriter = XmlWriter.Create(memoryStream, xmlWriterSettings))
            {
                dcSerializer.WriteObject(xWriter, obj);
                xWriter.Flush();
                //return Encoding.UTF8.GetString(memoryStream.ToArray());
                memoryStream.Position = 0;
                return memoryStream;
            }
}
21Dec/090

Secure WCF REST webservice – part 1 – Validate XML with Schema

I have spent a good amount of time workig to implement a good XML validation method. I followed may leads and ended with a simple solution.

My goals were:
* use WCF/REST
* Use a Schema to validate the incoming XML request
* Extend the deserialize method turn prohibit DTDs and to disable external entities
* Filter IPs based on a list in the Config file
* Use the newer WebServiceHost2 from the WCF REST Starter Kit

Problems I had:
* I tried extending IDispatchMessageInspector and IClientMessageInspector to add schema validation. This worked great on WS Services (wsHttpBinding), but I could not get it to work on WebServices (webHttpBinding). I could not find any exampels of working solution on the net on how to do this with web services. (here is the blog post on what I did come up with). I abandoned this approach.

* Schema validation is done on the xml before it is derialized or when it is deserialized to an object. Because I could not access the deserialization before accepting the incoming xml request, I was forced to have the incoming object type 'XElement' rather than the destination object.

My solution:
* I used the new WCF REST Starter Kit. This reduces the confit file to almost nothing. The endpoints are set automatically. All adjustments can be done thru attributes on the service method itself.

Here is my config file:

<?xml version="1.0"?>
<configuration>
  <appSettings>
     ...
  </appSettings>

  <system.web>
		<compilation debug="true"/>
  </system.web>

  <system.serviceModel>
		<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
  </system.serviceModel>
</configuration>

My Service:

// The following line sets the default namespace for DataContract serialized typed to be ""
[assembly: ContractNamespace("", ClrNamespace = "ThisIsMyService")]

namespace ThisIsMyService
{
    // TODO: Please set IncludeExceptionDetailInFaults to false in production environments
    [ServiceBehavior(IncludeExceptionDetailInFaults = true), AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed), ServiceContract]
    public partial class Service
    {
        [WebHelp(Comment = "This is my service")]
        [WebInvoke(UriTemplate = "MyService")]
        [OperationContract]
        public XElement MyService(XElement requestXml)
        {
            // Schema validation and deserialization are both done at the same time.
            // If there is a problem, null is returned and an exception is thrown with a HTTPStatusCode of Bad Request.
            var validatedObject = Helper.XmlToObject(requestXml, typeof(RequestObject),
                ConfigurationManager.AppSettings["SchemaPath"].ToString(),
                ConfigurationManager.AppSettings["SchemaNamespace"].ToString());

            // I do all the process and other work in the helper class to keep this clean.
            if (validatedObject is RequestObject)
                return new Helper().DoStuff((RequestObject)validatedObject);

            // If there is problem validating the incoming request XML, then the validated object will be null
            // Error validating request - return nothing
            return new XElement("root");
        }
    }
}

My service is very basic. All the logic is done in the helper class.

My helper class contains the static validation XMLtoObject method and the methods for doing the work of the service.

When you deserialize XML to an object, you can add a schema that will be used to check the XML.
What you don't easily find in the documentation, is the fact that the Schema must be read and validated before it can be added to the reader that reads and deserializes the incoming xml request.

public class EngineServiceHelper
{
    /// <summary>
    /// A schema is an XML file like all the rest.
    /// It also must be loaded and deserialized.
    /// To use a schema, it must be placed in a XmlSchemaSet.
    /// </summary>
    /// <param name="xml"></param>
    /// <param name="DestinationType"></param>
    /// <param name="schemaPath"></param>
    /// <param name="xmlNamespace"></param>
    /// <returns></returns>
    public static object XmlToObject(XElement xml, Type DestinationType, string schemaPath, string xmlNamespace)
    {
        ErrorMessage = string.Empty;
        ErrorsCount = 0;

        XmlSchemaSet schemaSet = new XmlSchemaSet();
        schemaSet.ValidationEventHandler += new ValidationEventHandler(settings_ValidationEventHandler);
        schemaSet.Add(xmlNamespace, schemaPath);

        if (schemaSet.Count > 0)
        {
            try
            {
                // Set the setting for reading the Schema file
                XmlReaderSettings schemaSettings = new XmlReaderSettings();
                schemaSettings.ValidationType = ValidationType.Schema;
                schemaSettings.Schemas.Add(schemaSet);
                // To make the service more secure and prevent XML Bombs and such, disable DTDs
                xmlRequestSettings.ProhibitDtd = true;
                // Limit the size of the elements - 1024 = 1Kb
                schemaSettings.MaxCharactersFromEntities = 1024;
                // Adding the validation event handler prevents validation errors from throwing an exception.
                // We want to control when and how an exception is thrown.
                schemaSettings.ValidationEventHandler += new ValidationEventHandler(settings_ValidationEventHandler);
                // create the reader for reading the schema
                XmlReader schemaReader = XmlReader.Create(xml.CreateReader(), schemaSettings);

                // Set the settings for reading the incoming XML request
                XmlReaderSettings xmlRequestSettings = new XmlReaderSettings();
                // To make the service more secure and prevent XML Bombs and such, disable DTDs
                xmlRequestSettings.ProhibitDtd = true;
                // Limit the size of the elements - 1024 = 1Kb
                schemaSettings.MaxCharactersFromEntities = 1024;
                // Create the reader for reading the XML request.
                XmlReader xmlReader = XmlReader.Create(schemaReader, xmlRequestSettings);

                // Deserialize the XML to an object
                XmlSerializer serializer = new XmlSerializer(DestinationType, xmlNamespace);
                object returnObject = serializer.Deserialize(xmlReader);

                // If there are errors, throw an exception
                if (ErrorsCount > 0)
                    throw new Exception(ErrorMessage);

                // If ther are no problems, return the deserialized object
                return returnObject;
            }
            catch (Exception ex)
            {
                // Using the WebProtocolException in the WCF REST Starter Kit, you can throw
                // and exception and choose the HTTPStatusCode that will be displayed to the end user.
                throw new WebProtocolException(HttpStatusCode.BadRequest, "Your XML is invalid: " + ex.Message, null);
            }
        }
        return null;
    }

    /// <summary>
    /// Check the error severity and create the error message.
    /// Increment the error counter.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public static void settings_ValidationEventHandler(object sender, ValidationEventArgs e)
    {
        if (e.Severity == XmlSeverityType.Error)
        {
            ErrorMessage = "ERROR: " + ErrorMessage + e.Message + "\r\n";
            ErrorsCount++;
        }
        else
        {
            ErrorMessage = "WARNING: " + ErrorMessage + e.Message + "\r\n";
            ErrorsCount++;
        }
    }
}

The validation event handler allows you to catch the validation errors and handle them yourself.
I am checking the error severity and returning a message that reflects it.

4Dec/090

Preventing XML Bombs

The Nobember (2009) issue of Msdn Magazine has a great article on XML Bombs and XML External Entity Attacks (DoS attatcks).

This was extremely useful to us as we are in the process of publishing a webservice that will be extensively used. Our current service is attacked regularly. Luckily, the attacks have been pretty basic and our security protects us. We were vulnerable to these types of attacks, but no longer are.

Example of an XML Bomb
XML Bombs use the XML document type definition (DTD) to create a piece of XML that, when parsed, will inflate to a huge size and consume all the resources on your machine.

Here is an example of such an attack from the article:

<?xml version="1.0"?>
<!DOCTYPE lolz [
   <!ENTITY lol "lol">
   <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
   <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
   <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
   <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
   <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
   <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
   <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
   <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>

The above code loops internally to create an object of about 3GB of memory. Impressive.
The 2nd entity consists of 10 of the 1st entity.
The 3rd entity consists of 10 of the 2nd entity (10 x 10 of the first).
The 4th entity consists of 10 of the 3rd entity (10 x 10 x 10 first).
And so on. The final XML is huge.

Preventing XML Bombs can be easily done by disabing inline DTDs.

Doing so is different in .Net 3.5 vs .Net 4.0

In .Net 3.5 you can use the ProhibitDtd boolean in the XmlTextReader or XmlReaderSettings.

// default is false
XmlTextReader reader = new XmlTextReader(myStream);
reader.ProhibitDtd = true; 

or 

// default is true
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = true;
XmlTextReader reader = new XmlTextReader(myStream, settings);

In .Net 4.0 you can use the DtdProcessing property. It can be set to Prohibit or Ingore. The ProhibitDtd property has been removed in 4.0.

// Prohibit will throw an exception if there is a <!DOCTYPE>
XmlREaderSettings settings = new XmlReaderSettngs();
settings.DtdProcessing = DtdProcessing.Prohibit;
XmlTextReader reader = new XmlTextReader(myStream, settings);

or

// Ingore will NOT throw an exception if there is a <!DOCTYPE>. It will ignore all DTDs.
XmlREaderSettings settings = new XmlReaderSettngs();
settings.DtdProcessing = DtdProcessing.Prohibit;
XmlTextReader reader = new XmlTextReader(myStream, settings);

If you would like to parse the DTDs, you should limit the size of the expanded DTDs.
This is easily done using the settings.

// default is true
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1024; // 1 KB
XmlTextReader reader = new XmlTextReader(myStream, settings);
Tagged as: , No Comments
30Nov/090

Adding Multiple Namespaces to an XDocument/XElement

Lets say you want 3 namespaces added to your document.
You would define each one with the XNamespace property:

XNamespace defaultNS = "urn://xml.voodoo.net/vd/vd-1.0";
XNamespace a = "urn://xml.voodoo.net/vd/activity-1.0";
XNamespace f = "urn://xml.voodoo.net/vd/formating-1.0";

One of the namespaces will be your default.
When you create your rood element, you first add the default and then the other after.
The other 2 are added as you see below:

XElement rootElement = new XElement(defaultNS + "root",
   new XAttribute(XNamespace.Xmlns + "f", f.NamespaceName),
   new XAttribute(XNamespace.Xmlns + "a", a.NamespaceName));

To access the other namespaces, you

XElement somethingElement = new XElement(a + "something");
somethingElement.Value = "stuff and more stuff";
rootElement.Add(somethingElement);

The result will look like this:

<root xmlns:f="urn://xml.voodoo.net/vd/formating-1.0" xmlns:a="urn://xml.voodoo.net/vd/activity-1.0" xmlns="urn://xml.voodoo.net/vd/vd-1.0">
      <a:something>stuff and more stuff</a:something>
</root>
Tagged as: No Comments
13Oct/090

Add a namespace and attributes to an XElement

Adding a namespace to an XElement is very very simple. However, there is one thing that will throw you off.

The root element has the namespace in most cases.
Microsoft thinks that the first child element may want a different namespace.
When you add the namespace to the first element, the children receives an empty xmlns attribute. If you want to prevent this, you have to add the namespace to the children also. This will prevent the empty xmlns attribute from showing.

Why is the empty xmlns added? Ask MS.

// Create a namespace element
XNamespace xmlns = "urn://some.strange.place.net/something/good-1.0";

// Add the namespace element to the root element name.
// The namespace is sort of an attribute, but is not added like one.
XElement rootElement = new XElement(xmlns + "root");

// You must also add the namespace to the first child element.
// If you don't you will get an empty namespace attribute in the element.
// Adding the same namespace to the children prevents the empty namespace from showing.
XElement customersElement = new XElement(xmlns + "customers");
rootElement.Add(customersElement);

XElement customerElement = new XElement(xmlns + "customer");
customersElement.Add(customerElement);

// Attributes are added just like child nodes. Very simple.
XAttribute typeAttribute = new XAttribute("customerType", "Corporate");
customersElement.Add(typeAttribute);

XElement nameElement = new XElement("Name", "John Smith");
customerElement.Add(nameElement);

This will create an xml document that looks like this:

<root xmlns='urn://some.strange.place.net/something/good-1.0'>
     <customers>
          <customer customerType='Corporate'>
               <Name>John Smith</Name>
          </customer>
     </customers>
</root>
Tagged as: No Comments
1Oct/090

Traversing an XML document (with a namespace) (part 2)

This xml document contains a namespace. This complicates traversing the document a little bit, but not much if you know how.

First the xml document:

<?xml version="1.0" encoding="UTF-8" ?>
<bla xmlns='urn://xml.somexml.net/xrda/xrda-1.0'>
   <response>
      <session secconds='10000' user='user@hotmail.com' username='My Name'>
         <message>This is my message!</message>
      </session>
   </response>
</bla>

We must declare the namespace and then use it when specifying the elements.

private XPathNavigator xpn;
private XmlNamespaceManager ns;

private XElement AcceptMessage(XmlElement xml)
{
if (xml == null)
   return new XElement("response");

// Declair the namespace
xpn = xml.CreateNavigator();
ns = new XmlNamespaceManager(xpn.NameTable);
ns.AddNamespace("x", xpn.NamespaceURI); // the x is our nickname for the namespace

// First lets get the content of the message.
string message = GetElement("x:message"); // add the x: in front of the element name

// Now let's get the attributes of the session element
string username = GetAttributeValue("x:session", "username"); // add the x:
string user = GetAttributeValue("x:session", "user"); // add the x:
string secconds = GetAttributeValue("x:session", "secconds"); // add the x: 

}
public string GetElement(string element)
{
    // The XPath syntax must be correct - add to slashes in front of the text 'message'.
    // If the XPath syntax is not correct you may get an exception or null.
    try
    {
        // Add the namespace to the select
        XPathNavigator navResult = xpn.SelectSingleNode("//" + element, ns);

        if (navResult != null)
            return navResult.InnerXml;

        return string.Empty;
    }
    catch (Exception ex)
    {
        return string.Empty;
    }
}
public string GetAttributeValue(string element, string attributeName)
{
    try
    {
        // Add the namespace to the select
        XPathNavigator navResult = xpn.SelectSingleNode("//" + element, ns);
        if (navResult != null)
        {
            // Once you have the 'navResult' you no longer need to specify the namespace.
            // This is becuase the navResult contains no namespace information.
            // add and empty string for the namepace URI
            string value = navResult.GetAttribute(attributeName, string.Empty);
            return value;
        }
        else
            return string.Empty;
    }
    catch (Exception ex)
    {
        return string.Empty;
    }
}
Tagged as: No Comments
1Oct/090

Traversing an xml document (part 1)

This explains how to process a simple xml document.

First the xml document:

<?xml version="1.0" encoding="UTF-8" ?>
<bla>
   <response>
      <session secconds='10000' user='user@hotmail.com' username='My Name'>
         <message>This is my message!</message>
      </session>
   </response>
</bla>

We will start from an XmlDocument (or an XmlElement - about the same thing)

The object is to get the content of the message element and the attributes in the session element.

private XElement AcceptMessage(XmlElement xml)
{
if (xml == null)
   return new XElement("response");

// First lets get the content of the message.
string message = GetElement("message");

// Now let's get the attributes of the session element
string username = GetAttributeValue("session", "username");
string user = GetAttributeValue("session", "user");
string secconds = GetAttributeValue("session", "secconds");

}

SelectSingleNode selectes the first node of the element specified.
The result is most often an XPathNavigator. Each selection will return a part of the xml from the node/element you searched for.
Selecting the 'message' node will return only that node. If message had child nodes, they would also be returned.

public string GetElement(string element)
{
    // The XPath syntax must be correct - add to slashes in front of the text 'message'.
    // If the XPath syntax is not correct you may get an exception or null.
    try
    {
        XPathNavigator navResult = xpn.SelectSingleNode("//" + element);

        if (navResult != null)
            return navResult.InnerXml;

        return string.Empty;
    }
    catch (Exception ex)
    {
        return string.Empty;
    }
}

GetAttribute returns the value of the attribute you specify in the curren node/element.
In this case, we selected the 'session' element. The session element has one child (the message element). The navResult contains only the session element and its children.
GetAttribute returns the string value of our attribute.
There is no namespace uri to specify, so we leave it empty.

public string GetAttributeValue(string element, string attributeName)
{
    try
    {
        XPathNavigator navResult = xpn.SelectSingleNode("//" + element);
        if (navResult != null)
        {
            string value = navResult.GetAttribute(attributeName, string.Empty);
            return value;
        }
        else
            return string.Empty;
    }
    catch (Exception ex)
    {
        return string.Empty;
    }
}

NEXT: adding a namespace to the XML complicates it. See how!

Tagged as: No Comments
27Aug/090

WCF – Service using WebInvoke

Most services are more complicated than the simple service I just described.

Most services require you to send in XML or an object (an object which has been serialized to XML).

This means we need an object to pass in.
I created the PersonObject for this.
The object being sent in must have a DataContract. The DataContract specifies what properties are seen by the webservice, and which properties are required.
In this simple example, there are no required properties (or DataMembers).

namespace SandboxObjects
{
    [DataContract]
    public class PersonObject
    {
        [DataMember]
        public string lastName;
        [DataMember]
        public string firstName;
    }
}

The Interface become more complex than the Simple Example.
We use the 'WebInvoke' attribute instead of 'WebGet'.
We specify the Method as POST.
The UriTemplate is Hello2 (same as the method name.. for now... more on that later)
We also specify the request and the response format as XML (Json is another posibility but not discussed here)
Lastly the input and output types are both PersonObject.

[OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "Hello2", RequestFormat = WebMessageFormat.Xml, ResponseFormat = WebMessageFormat.Xml, BodyStyle = WebMessageBodyStyle.Bare)]
    SandboxObjects.PersonObject Hello2(SandboxObjects.PersonObject person);

I am just returning the object sent in to make it simple:

    public SandboxObjects.PersonObject Hello3(SandboxObjects.PersonObject person)
    {
        return person;
    }

The Web.config setting are identical to for this method as they are for the Simple Service example.

Calling this service is different. You can't call it from the browser. If you do, you get the error 'Method not allowed'

http://localhost:3041/SandboxWebsite/TestService.svc/Web/Hello3

Before calling the service, the object must be serialized:

SandboxObjects.PersonObject p = new SandboxObjects.PersonObject();
p.firstName = "Joe";
p.lastName = "Smith";
Stream xmlStream = ObjectToXml(p);
XmlDocument xDoc = new XmlDocument();
xDoc.Load(xmlStream);

string xmlString = xDoc.InnerXml;

Simple method to serialize an object:

public static Stream ObjectToXml(Object obj)
{
    MemoryStream memoryStream = new MemoryStream();
    DataContractSerializer dcSerializer = new DataContractSerializer(obj.GetType());
    XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
    xmlWriterSettings.Encoding = new UTF8Encoding(false);
    xmlWriterSettings.ConformanceLevel = ConformanceLevel.Document;
    xmlWriterSettings.Indent = true;
    //xmlWriterSettings.OmitXmlDeclaration = true;

    using (XmlWriter xWriter = XmlWriter.Create(memoryStream, xmlWriterSettings))
    {
        dcSerializer.WriteObject(xWriter, obj);
        xWriter.Flush();
        //return Encoding.UTF8.GetString(memoryStream.ToArray());
        memoryStream.Position = 0;
        return memoryStream;
    }
}

No that you have the serialized object, you can call the servie. This simple example does so using the WebClient object:

string url = "http://localhost:3041/SandboxWebsite/TestService.svc/Web/Hello3";
var webClient = new WebClient();
webClient.Headers.Add("Content-Type", "application/xml; charset=utf-8");
string p1 = webClient.UploadString(url, "POST", xmlString);

More comple, but more useful method using HttpWebRequest:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
byte[] bytes = Encoding.UTF8.GetBytes(xmlString);
request.ContentLength = bytes.Length;
request.ContentType = "text/xml; encoding='utf-8'";
Stream requestStream = request.GetRequestStream();
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();

// get response
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

// process response
XmlDocument xmlResponse = new XmlDocument();
if (response.StatusCode == HttpStatusCode.OK)
{
    Stream responseStream = response.GetResponseStream();
    XmlTextReader xmlReader = new XmlTextReader(responseStream);
    xmlResponse.Load(xmlReader);
    responseStream.Close(); // close connections
    xmlReader.Close(); // close connections
    xmlReader = null; // release the objects
    responseStream = null; // release the objects
}
response.Close(); // close connections
requestStream = null; // release the objects
response = null; // release the objects
request = null; // release the objects

return XMLResponse; // return the XML response!
Tagged as: , No Comments
19Aug/090

Deserialize XML to an Object

One of the more useful tools to have in your toolbox is a method or class to convert an Object to XML and XML to an Object.

Converting XML to an object is very easy.

You need your destination object:

public class PersonObject
{
    public string lastName;
    public string firstName;
    public string gender;
    public string email;
    public int age;
    public int telephone;
    public string city;
    public string state;

    public PersonObject() {}
}

Most likely you will recieve your XML from a web service. Here is some simple code to call a webservice and get the XML response:

StringBuilder sb = new StringBuilder();
byte[] buf = new byte[8192];
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.someurl.com/getPerson?...");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream resStream = response.GetResponseStream();

string tempString = null;
int count = 0;
do
{
    count = resStream.Read(buf, 0, buf.Length);
    if (count != 0)
    {
        tempString = Encoding.ASCII.GetString(buf, 0, count);
        sb.Append(tempString);
    }
}
while (count > 0); 

PersonObject person = (PersonObject)XmlToObject(sb.ToString(), typeof(PersonObject));

Here is the method to convert the XML to the PersonObject:

private object XmlToObject(string XmlToConvert, Type DestinationType)
{
    XmlSerializer serializer = new XmlSerializer(DestinationType);
    StringReader stringReader = new StringReader(XmlToConvert);
    XmlTextReader xmlReader = new XmlTextReader(stringReader);
    object returnObject = serializer.Deserialize(xmlReader);
    xmlReader.Close();
    stringReader.Close();
    return returnObject;
}

It is just a few lines of code. Very simple.
You will notice the PersonObject does not contain any XML attributes for basic use.

Tagged as: No Comments