3
\$\begingroup\$

I've run into the need to deserialize XML that returns from an http request. I've done some light work with XML deserialization in the past but that was against files on disk.

While attempting to write the code I noticed that many of the methods in HttpWeb* and XmlReader had both an async and a regular version. I'd glossed over await/async material in the past but have never done anything with it. This seemed like a good opportunity to kill two birds.

Below is my current attempt at both types of processing. You should be able to copy/paste the code into a C# Console App, add references to System.Runtime.Serialization and System.Xml.Linq, and then run.

I think I'm using everything properly and I'm actually pretty pleased with the code. However, I don't pretend to know enough about what I'm doing here yet to be confident that there aren't pitfalls that I'm missing.

using System;
using System.Linq;
using System.Net;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
class Program
{
 static void Main() {
 string url = @"http://www.holidaywebservice.com/HolidayService_v2/HolidayService2.asmx/GetHolidaysForDateRange?countryCode=UnitedStates&startDate=2000年01月01日T00:00:00&endDate=2014年01月01日T00:00:00";
 // Run Synchronous
 var sw1 = new System.Diagnostics.Stopwatch();
 sw1.Start();
 DoStuff(url);
 sw1.Stop();
 // Run Asynchronous
 var sw2 = new System.Diagnostics.Stopwatch();
 sw2.Start();
 DoStuffAsync(url).Wait();
 sw2.Stop(); 
 Console.WriteLine("Sync Elapsed:{0}", sw1.Elapsed.TotalMilliseconds);
 Console.WriteLine("Async Elapsed:{0}", sw2.Elapsed.TotalMilliseconds);
 Console.ReadKey();
 } 
 private static void DoStuff(string url) {
 var stream = GetHttpResponse(url, @"application/xml");
 // Xml Processing
 ProcessXmlStream(stream);
 }
 private static async Task DoStuffAsync(string url) {
 var response = await GetHttpResponseAsync(url, @"application/xml");
 // Xml Processing
 await ProcessXmlStreamAsync(response);
 }
 private static WebResponse GetHttpResponse(string url, string contentType) {
 var request = HttpWebRequest.CreateHttp(url);
 request.ContentType = contentType;
 //string creds = userName + ":" + password;
 //creds = Convert.ToBase64String(Encoding.Default.GetBytes(creds));
 //request.Headers["Authorization"] = "Basic " + creds;
 return request.GetResponse();
 }
 private static async Task<WebResponse> GetHttpResponseAsync(string url, string contentType) {
 var request = HttpWebRequest.CreateHttp(url);
 request.ContentType = contentType;
 //string creds = userName + ":" + password;
 //creds = Convert.ToBase64String(Encoding.Default.GetBytes(creds));
 //request.Headers["Authorization"] = "Basic " + creds;
 return await request.GetResponseAsync();
 }
 private static void ProcessXmlStream(WebResponse response) {
 using (var xReader = XmlReader.Create(response.GetResponseStream())) { 
 var dcs = new DataContractSerializer(typeof(XmlElement));
 xReader.MoveToContent();
 while (xReader.Read()) {
 switch (xReader.NodeType) {
 case XmlNodeType.Element:
 var e = dcs.ReadObject(xReader, false) as XmlElement;
 if (e != null) {
 ProcessResults(e);
 }
 break;
 }
 }
 }
 }
 private static async Task ProcessXmlStreamAsync(WebResponse response) {
 using (var xReader = XmlReader.Create(response.GetResponseStream(), new XmlReaderSettings() { Async = true })) {
 var dcs = new DataContractSerializer(typeof(XmlElement));
 await xReader.MoveToContentAsync();
 while (await xReader.ReadAsync()) {
 switch (xReader.NodeType) {
 case XmlNodeType.Element:
 var e = dcs.ReadObject(xReader, false) as XmlElement;
 if (e != null) {
 ProcessResults(e);
 }
 break;
 }
 }
 }
 }
 private static void ProcessResults(XmlElement element) {
 var e = XElement.Parse(element.OuterXml);
 var results = from p in e.DescendantsAndSelf()
 where p.Name.LocalName == "Holiday"
 let ns = p.Name.Namespace
 select new {
 HolidayCode = (string)p.Element(ns + "HolidayCode"),
 HolidayDate = (string)p.Element(ns + "Date"),
 };
 foreach (var item in results) {
 Console.WriteLine("HolidayCode: {0} | HolidayDate: {1}", item.HolidayCode, item.HolidayDate);
 }
 }
}
asked Jul 26, 2014 at 9:20
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

I understand that this is an educational exercise, but naming is important. One and two letter names are highly discouraged. When Mr. Maintainer has to map letters to meanings it becomes difficult for him to focus on what's actually happening, because he has to constantly remember thate means element and dcs is a DataContractSerializer. I'm not even going to mention how terrible DoStuff and DoStuffAsync are. Oops, I just did. =;)-

It's also standard in C# to put opening braces on a new line instead of using Java style Egyptian braces. A dev who swims in C# on a regular basis may have a hard time reading this code as it is. You were consistent though, so I can't complain a whole lot about it.

I question the use of a switch statement in ProcessXmlStream. Typically, switch is used when there are multiple cases to test. I think an If statement would work just fine there.

answered Jul 27, 2014 at 12:23
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.