Thursday, May 22, 2014

C# class with Methods to Get Json or Xml Data Into List

Below is a class of columns returned by a web service API, with methods to get that data in either Json or Xml form, and send that data into a List of the class properties.

The controller ActionResult (Site is .Net MVC) using this class either uses:

BusInfo bi = new Models.BusInfo();
            IEnumerable model = bi.getDataX();//gets data via xml from web service
            ViewData["PageTitle"] = "Business Information";
            return View(model);

or

BusInfo bi = new Models.BusInfo();
            IEnumerable model = bi.getDataJ();//gets data in json form from web service
             ViewData["PageTitle"] = "Business Information";
            return View(model);

depending on whether I want to get Json or Xml.

I have 3 Xml retrieval methods. The default one used above places the Xml data in a DataSet, then to the list.
The 2nd, getDataX2, has no middleman. Data goes from Xml to list, via XmlReader.
The 3rd, getDataX3, converts Xml to Json, thence to list.

The class is below:

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Data;
using System.Web;
using System.Web.Mvc;
using System.Net;
using System.Runtime.Serialization.Json;//used in getDataJ
using System.Xml;
using System.Xml.Linq;

namespace SiteName.Models
{
    public class BusInfo
    {
        public string title { get; set; }
        public string url { get; set; }
        public string description { get; set; }
        public string keywords { get; set; }
        public string category { get; set; }

        readonly string baseUrij = "http://api.sba.gov/rec_sites/all_sites/keywords.json";//json
        readonly string baseUrix = "http://api.sba.gov/rec_sites/all_sites/keywords.xml";//xml

        public BusInfo()
            : base()
        {

        }

        //this constructor is needed if using getDataX2 because:
        //we need an alternative while looping through the reader, to setting a BusInfo instance for each group of properties
        //in order to Add to List because the list ends up with all members set to the value of the last iteration
        //ie, bi.Add(b) just puts a reference to 'b' in each row when set inside the reader. change b, change every member of bi
        //instead we're setting local variables that are fed directly into bi.Add as a new BusInfo() for each iteration
        public BusInfo(string t, string u, string d, string k, string c)
        {
            title = t;
            url = u;
            description = d;
            keywords = k;
            category = c;
        }
        
        public List getDataJ()//for json source, json to list
        {

            string uri = baseUrij;
            WebRequest wr = WebRequest.Create(uri);
            WebResponse wrs = wr.GetResponse();
            DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(List));
            List bi = (List)jsonSerializer.ReadObject(wrs.GetResponseStream());
            return bi;

        }//end getDataJ

        public List getDataX()//for xml source xml to dataset to list
        {
            //parent node in dataset becomes 'sites_id' in place of 'sites site'
            string uri = baseUrix;
            HttpWebRequest wr = (HttpWebRequest) WebRequest.Create(uri);
            wr.Method = "GET";
            List bi = new List();
            DataSet ds = new DataSet();
            ds.ReadXml(uri);
            if (ds != null)
            {
                if (ds.Tables.Count > 0)
                {
                    foreach (DataTable dt in ds.Tables)
                    {
                        foreach (DataRow dr in dt.Rows)
                        {
                            BusInfo b = new BusInfo();                            
                            foreach (DataColumn dc in dr.Table.Columns)
                            {
                                switch (dc.ColumnName)
                                {
                                    case "title":
                                        b.title = dr[dc.ColumnName].ToString().Trim();
                                        break;
                                    case "url":
                                        b.url = dr[dc.ColumnName].ToString().Trim();
                                        break;
                                    case "description":
                                        b.description = dr[dc.ColumnName].ToString().Trim();
                                        break;
                                    case "keywords":
                                        b.keywords = dr[dc.ColumnName].ToString().Trim();
                                        break;
                                    case "category":
                                        b.category = dr[dc.ColumnName].ToString().Trim();
                                        break;
                                    default:
                                        break;
                                }                               
  
                            }
                            bi.Add(b);
                            
                        }
                    }
                }
            }
            return bi;

        }//end getDataX

        public List getDataX2()//for xml source xml to list direct - no middleman
        {
            List bi = new List();
            string uri = baseUrix;
            string em = "";
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreComments = true;
            settings.DtdProcessing = DtdProcessing.Parse;
            int bc = 0;
            bool runBiAdd = false;
                
            try
            {
                using (XmlReader reader = XmlReader.Create(uri, settings))
                {
                    //cannot use an instance of BusInfo inside reader - must use local variables
                    string btitle = "";
                    string burl = "";
                    string bdescription = "";
                    string bkeywords = "";
                    string bcategory = "";
                    while (reader.Read())
                    {                       
            
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            runBiAdd = false;
                            switch (reader.Name)
                            {
                                case "title":
                                    bc++;
                                    btitle = reader.ReadString().ToString();
                                    runBiAdd = true;
                                    break;
                                case "url":
                                    bc++;
                                    burl = reader.ReadString().ToString();
                                    runBiAdd = true;
                                    break;
                                case "description":
                                    bc++;
                                    bdescription = reader.ReadString().ToString();
                                    runBiAdd = true;
                                    break;
                                case "keywords":
                                    bc++;
                                    bkeywords = reader.ReadString().ToString();
                                    runBiAdd = true;
                                    break;
                                case "category":
                                    bc++;
                                    bcategory = reader.ReadString().ToString();
                                    runBiAdd = true;
                                    break;
                                default:
                                    break;
                            }
                            if (runBiAdd = true && bc == 5)
                            {
                                bi.Add(new BusInfo(btitle,burl,bdescription,bkeywords,bcategory));//see notes by constructor above
                                bc = 0;
                            }                                
                        }                                
                    }                                
                }                                 
            }
            catch (Exception ex)
            {
                em = "An Error Occured: " + ex.Message;
                bi.Clear();
            } 
            
            return bi;
        }//end getDataX2

        //gets xml into json, then into list
        //have to know structure of xml schema
        public List getDataX3()
        {
            List bi = new List();
            string uri = baseUrix;
            bi.Clear();
            string em = "";
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreComments = true;
            settings.DtdProcessing = DtdProcessing.Parse;
            XmlDocument doc = new XmlDocument();
            try
            {
                using (XmlReader reader = XmlReader.Create(uri, settings))
                {
                    while (reader.Read())
                    {
                        doc.Load(reader);
                    }
                }
                
                string json = XMLToJson.XmlToJSON(doc);
                
                JObject jo = JObject.Parse(json);
                foreach (var v in jo["sites"]["site"])
                {
                    BusInfo b = new BusInfo();
                    b.title = v["title"].ToString();
                    b.url = v["url"].ToString();
                    b.description = v["description"].ToString();
                    b.keywords = v["keywords"].ToString();
                    b.category = v["category"].ToString();
                    bi.Add(b);

                }
            }
            catch (Exception ex)
            {
                em = "An Error Occured: " + ex.Message;              
            } 
            return bi;
        }//end getDataX3

     }
  
}

Using XmlReader and XmlReaderSettings in C3 Asp.Net MVC

I already had methods for retrieving both Json and Xml formatted data from an API web service.
What I still couldn't get to work was getting the data in Xml and converting it cleanly to Json.
Problem thus far are the child nodes and the fact that the conversion methods kept leaving escape slashes in the Json string, despite running it through Regex.Unescape.

And in truth, there may be no logical reason why I should need to do such a conversion, since my other 2 methods cleanly placed data from both formats into my webgrid's class.

My Xml method did it by first reading all the data into a dataset, from whence the data went into my class List feeding the webgrid.

I wanted another way of dealing with the Xml, for better, worse, or just for variety and learning sake.
Thanks to this great blog article by Saiful Alam, at http://asp-net-example.blogspot.com/2009/05/xmlreadersettings-how-to-use.html, I got my 2nd Xml to List method.


public List getDataX2()//for xml source xml to list direct - no middleman
        {
            List bi = new List();
            string uri = baseUrix;
            string em = "";
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreComments = true;
            settings.DtdProcessing = DtdProcessing.Parse;
            int bc = 0;
            bool runBiAdd = false;
                
            try
            {
                using (XmlReader reader = XmlReader.Create(uri, settings))
                {
                    //cannot use an instance of BusInfo inside reader - must use local variables
                    string btitle = "";
                    string burl = "";
                    string bdescription = "";
                    string bkeywords = "";
                    string bcategory = "";
                    while (reader.Read())
                    {                       
            
                        if (reader.NodeType == XmlNodeType.Element)
                        {
                            runBiAdd = false;
                            switch (reader.Name)
                            {
                                case "title":
                                    bc++;
                                    btitle = reader.ReadString().ToString();
                                    runBiAdd = true;
                                    break;
                                case "url":
                                    bc++;
                                    burl = reader.ReadString().ToString();
                                    runBiAdd = true;
                                    break;
                                case "description":
                                    bc++;
                                    bdescription = reader.ReadString().ToString();
                                    runBiAdd = true;
                                    break;
                                case "keywords":
                                    bc++;
                                    bkeywords = reader.ReadString().ToString();
                                    runBiAdd = true;
                                    break;
                                case "category":
                                    bc++;
                                    bcategory = reader.ReadString().ToString();
                                    runBiAdd = true;
                                    break;
                                default:
                                    break;
                            }
                            if (runBiAdd = true && bc == 5)
                            {
                                bi.Add(new BusInfo(btitle,burl,bdescription,bkeywords,bcategory));//see notes by constructor above
                                bc = 0;
                            }                                
                        }                                
                    }                                
                }                                 
            }
            catch (Exception ex)
            {
                em = "An Error Occured: " + ex.Message;
                bi.Clear();
            } 
            
            return bi;
        }//end getDataX2


One issue I didn't consider while making this method, was the bugaboo when I attempted to keep reusing an instance of my BusInfo class, to add to my List during the reader's iterations.
As those of you who are already laughing at me already knew (however many "those-of-you"s there are), within the scope of this code, setting properties of a BusInfo instance for each iteration of the reader, in order to then add to the list, eg: BusInfoList.Add(BusInfoInstance), ends up changing all previous items in the list to the latest, and not so greatest, property values added to the newest item.
To fix this, I gave the class a constructor override with the 5 class properties as parameters, hence giving me the list.Add line "bi.Add(new BusInfo(btitle,burl,bdescription,bkeywords,bcategory));"

The constructors I added to the class:

public BusInfo()
            : base()
        {
        }
       
        public BusInfo(string t, string u, string d, string k, string c)
        {
            title = t;
            url = u;
            description = d;
            keywords = k;
            category = c;
        }