Wednesday 31 August 2011

Convert XML to JSON using C#

Here is the working solution I borrowed and modified from somewhere. But I forgot the original source. If you're the original author, please let me know if you'd like your name listed on this post.

 
public static class JSon
{
    public static string XmlToJSON(string xml)
    {
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xml);

        return XmlToJSON(doc);
    }
    public static string XmlToJSON(XmlDocument xmlDoc)
    {
        StringBuilder sbJSON = new StringBuilder();
        sbJSON.Append("{ ");
        XmlToJSONnode(sbJSON, xmlDoc.DocumentElement, true);
        sbJSON.Append("}");
        return sbJSON.ToString();
    }

    //  XmlToJSONnode:  Output an XmlElement, possibly as part of a higher array
    private static void XmlToJSONnode(StringBuilder sbJSON, XmlElement node, bool showNodeName)
    {
        if (showNodeName)
            sbJSON.Append("\"" + SafeJSON(node.Name) + "\": ");
        sbJSON.Append("{");
        // Build a sorted list of key-value pairs
        //  where   key is case-sensitive nodeName
        //          value is an ArrayList of string or XmlElement
        //  so that we know whether the nodeName is an array or not.
        SortedList<string, object> childNodeNames = new SortedList<string, object>();

        //  Add in all node attributes
        if (node.Attributes != null)
            foreach (XmlAttribute attr in node.Attributes)
                StoreChildNode(childNodeNames, attr.Name, attr.InnerText);

        //  Add in all nodes
        foreach (XmlNode cnode in node.ChildNodes)
        {
            if (cnode is XmlText)
                StoreChildNode(childNodeNames, "value", cnode.InnerText);
            else if (cnode is XmlElement)
                StoreChildNode(childNodeNames, cnode.Name, cnode);
        }

        // Now output all stored info
        foreach (string childname in childNodeNames.Keys)
        {
            List<object> alChild = (List<object>)childNodeNames[childname];
            if (alChild.Count == 1)
                OutputNode(childname, alChild[0], sbJSON, true);
            else
            {
                sbJSON.Append(" \"" + SafeJSON(childname) + "\": [ ");
                foreach (object Child in alChild)
                    OutputNode(childname, Child, sbJSON, false);
                sbJSON.Remove(sbJSON.Length - 2, 2);
                sbJSON.Append(" ], ");
            }
        }
        sbJSON.Remove(sbJSON.Length - 2, 2);
        sbJSON.Append(" }");
    }

    //  StoreChildNode: Store data associated with each nodeName
    //                  so that we know whether the nodeName is an array or not.
    private static void StoreChildNode(SortedList<string, object> childNodeNames, string nodeName, object nodeValue)
    {
        // Pre-process contraction of XmlElement-s
        if (nodeValue is XmlElement)
        {
            // Convert  <aa></aa> into "aa":null
            //          <aa>xx</aa> into "aa":"xx"
            XmlNode cnode = (XmlNode)nodeValue;
            if (cnode.Attributes.Count == 0)
            {
                XmlNodeList children = cnode.ChildNodes;
                if (children.Count == 0)
                    nodeValue = null;
                else if (children.Count == 1 && (children[0] is XmlText))
                    nodeValue = ((XmlText)(children[0])).InnerText;
            }
        }
        // Add nodeValue to ArrayList associated with each nodeName
        // If nodeName doesn't exist then add it
        List<object> ValuesAL;

        if (childNodeNames.ContainsKey(nodeName))
        {
            ValuesAL = (List<object>)childNodeNames[nodeName];
        }
        else
        {
            ValuesAL = new List<object>();
            childNodeNames[nodeName] = ValuesAL;
        }
        ValuesAL.Add(nodeValue);
    }

    private static void OutputNode(string childname, object alChild, StringBuilder sbJSON, bool showNodeName)
    {
        if (alChild == null)
        {
            if (showNodeName)
                sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
            sbJSON.Append("null");
        }
        else if (alChild is string)
        {
            if (showNodeName)
                sbJSON.Append("\"" + SafeJSON(childname) + "\": ");
            string sChild = (string)alChild;
            sChild = sChild.Trim();
            sbJSON.Append("\"" + SafeJSON(sChild) + "\"");
        }
        else
            XmlToJSONnode(sbJSON, (XmlElement)alChild, showNodeName);
        sbJSON.Append(", ");
    }

    // Make a string safe for JSON
    private static string SafeJSON(string sIn)
    {
        StringBuilder sbOut = new StringBuilder(sIn.Length);
        foreach (char ch in sIn)
        {
            if (Char.IsControl(ch) || ch == '\'')
            {
                int ich = (int)ch;
                sbOut.Append(@"\u" + ich.ToString("x4"));
                continue;
            }
            else if (ch == '\"' || ch == '\\' || ch == '/')
            {
                sbOut.Append('\\');
            }
            sbOut.Append(ch);
        }
        return sbOut.ToString();
    }
}
 
To convert a given XML string to JSON, simply call XmlToJSON() function as below.
 
 
string xml = "<menu id=\"file\" value=\"File\"> " +
                  "<popup>" +
                    "<menuitem value=\"New\" onclick=\"CreateNewDoc()\" />" +
                    "<menuitem value=\"Open\" onclick=\"OpenDoc()\" />" +
                    "<menuitem value=\"Close\" onclick=\"CloseDoc()\" />" +
                  "</popup>" +
                "</menu>";

    string json = JSON.XmlToJSON(xml);
    // json = { "menu": {"id": "file", "popup": { "menuitem": [ {"onclick": "CreateNewDoc()", "value": "New" }, {"onclick": "OpenDoc()", "value": "Open" }, {"onclick": "CloseDoc()", "value": "Close" } ] }, "value": "File" }}
 

Output JSON from WCF RESTful Web Service


Under Microsoft WCF 4 framework, output either XML or JSON is fairly straightforward by simply setting a proper attribute property in your public service API function.

 
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyWebService
{
   [OperationContract]
   [WebGet(UriTemplate = "MyWebFunction/{userReq}", 
           ResponseFormat = WebMessageFormat.Json )]
   public string MyWebFunction(string userReq)
   {
      // do your magic here
      return "your magic result";
   }
   
   // your other public web function(s)
}
 

Tuesday 30 August 2011

Convert JSON text to object in Javascript

JSON (JavaScript Object Notation) is lightweight data-interchange structure which is fairly easy for human to read/write as well as for computer to process. GO here if you know more about it.

There are 2 cheap ways to consume JSON using javascript without a need of any 3rd party library. One is eval() function which is very fast. However it also compile and execute any javascript and impose potential security issue.
 

   function toObject(jsonText){
      return eval(jsonText);
   }

 

If this concerns you, a JSON parser should be used indeed. In browsers that provide native JSON support, call JSON.parse() function.

 

   function toObject(jsonTextn){
      return JSON.parse(jsonText);
   }

 

Display Close button on Input Box on iPhone

This can be easily archived by using new HTML5 input type: search. See the sample code below.


 
 

 


Friday 26 August 2011

JQuery Change Input Box Type

For security reason, some browsers such as IE don't allow modifying input type on the fly. Code snippet #1 won't know. In case you know exactly what you are doing and really want to modify the type dynamically for any good reasons. Here is a way to do so (see code snippet #2).

Code #1 - doesn't work in most of the browsers

 
Code #2 - works

 

Thursday 25 August 2011

Dynamically add meta tags in ASP.Net

Add the following code to master page on the page_load event handler. All it does is to add a keyword meta tag to the header of the html page from server-side, which opens a door to all other possibilities.

protected void Page_Load(object sender, EventArgs e)
{
   HtmlMeta meta = new HtmlMeta();
   meta.Name = "keywords";
   meta.Content = "ASP.Net, Web, meta tag";
   Header.Controls.Add(meta);
}

Thursday 18 August 2011

Visual Studio 2010 Load Test and Web Performance Test- Part 1

VS 2010 Ultimate subscribers can take advantage of advanced feature: Performance Test and Load Testing. The difference between performance test and load testing is:
Performance Test = how fast can your system be
Load Test = how much volume the system can process in a given interval

In Visual Studio 2010, a performance test must be created prior to setting up load testing as performance test (aka .webtest) is the only source of load test (aka .loadtest).

Will go through a working sample to dome how to set up performance test and load test in VS 2010.

Tuesday 16 August 2011

Reverse DNS lookup in Windows Command Line

Want to look up the domain name from a IP address in Windows platform? Use either of these 2 commands from your command prompt.

c:>ping -a xxx.xxx.xxx.xxx
or
c:>nslookup xxx.xxx.xxx.xxx

The output of each command is different but does one common thing returning the domain name of the IP address you enter.

Validation of viewstate MAC failed. System.Web.HttpException (0x80004005)

There are few workarounds provided by Microsoft back to 2008. See the original posting in here.

Personally I prefer solution#3 with Alex's improvement (see below). Luckily, .Net 4.0 or above has fix it within the framework.


 
public class BasePage : Page
{
private static string[] aspNetFormElements = new string[] 
{ 
"__EVENTTARGET",
"__EVENTARGUMENT",
"__VIEWSTATE",
"__EVENTVALIDATION",
"__VIEWSTATEENCRYPTED",
};

protected override void Render(HtmlTextWriter writer)
{
StringWriter stringWriter = new StringWriter();
HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter);
base.Render(htmlWriter);
string html = stringWriter.ToString();
int formStart = html.IndexOf("<form");
int endForm = -1;
if (formStart >= 0)
endForm = html.IndexOf(">", formStart);

if (endForm >= 0)
{
StringBuilder viewStateBuilder = new StringBuilder();
foreach (string element in aspNetFormElements)
{
int startPoint = html.IndexOf("<input type=\"hidden\" name=\"" + element + "\"");
if (startPoint >= 0 && startPoint > endForm)
{
int endPoint = html.IndexOf("/>", startPoint);
if (endPoint >= 0)
{
endPoint += 2;
string viewStateInput = html.Substring(startPoint, endPoint - startPoint);
html = html.Remove(startPoint, endPoint - startPoint);
viewStateBuilder.Append(viewStateInput).Append("\r\n");
}
}
}

if (viewStateBuilder.Length > 0)
{
viewStateBuilder.Insert(0, "\r\n");
html = html.Insert(endForm + 1, viewStateBuilder.ToString());
}
}

writer.Write(html);
}
}
 
 


Monday 15 August 2011

Trim leading zeros using javascript

Using simple RegExp in javacript can easily trim all leading zeros.


 
var numberString = ‘00220’;
var noLeadingZerosString = numberString.replace(/^0+/, ‘’); // noLeadingZerosString  = ‘220’;
 
 

Hide/remove transit stations from Google Map

I have been searching for the solution for a while on my recent real time transit project. The solution doesn't appear to be documented clearly. Here is my simplified working solution and hope it helps.


  

var latLng = new google.maps.LatLng(49.22587, -123.14044000000001); 
var mapOptions = {
zoom: 16,
minZoom: 10,
center: latLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};

var node = document.getElementById("map_canvas");
var map = new google.maps.Map(node, mapOptions);
var ntss = [{
  featureType: 'transit.station',
  elementType: 'all',
  stylers: [{ visibility: 'off' }]
}];

var mapType = new google.maps.StyledMapType(ntss, { name: 'ntsss' }); 

map.mapTypes.set('nstps', mapType);

map.setMapTypeId('nstps'); 

  

Thursday 11 August 2011

Use and transform NLog config in web.config

Ever wonder how to integrate your log platform configuration into your web.config so it can be transformed nicely into different environments, such as QA, staging and production environment? Below is a example config that I worked on for a public transit website.


The original web.config looks like
 
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <targets>
      <target xsi:type="File"
              name="FileLog"
              layout="${longdate} | ${level:uppercase=true} | ${logger} | ${message}"
              fileName="c:\logs\log_${shortdate}.log"/>
    <rules>
      <logger name="*" minlevel="Trace" writeTo="FileLog" />
    </rules>
  </nlog>
 

Your Release.config, for example, will set to below if the production has different path for log files.

 
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"
  xmlns:nlg="http://www.nlog-project.org/schemas/NLog.xsd">

...

<nlg:nlog  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <nlg:targets >
      <nlg:target xsi:type="File"
              name="FileLog"
              layout="${longdate} | ${level:uppercase=true} | ${logger} | ${message}"
              fileName="d:\logs\prod\Log_${shortdate}.log"  xdt:Transform="SetAttributes"  xdt:Locator="Match(name)" />
    </nlg:targets>
  </nlg:nlog>
</configuration>
 

Wednesday 10 August 2011

Enable .Net 4.0 in IIS 7.0/7.5

Go to C:\Windows\Microsoft.NET\Framework(64)\v4.0.30319 and run the command from command prompt using "Run as Administrator".

cd \
cd C:\Windows\Microsoft.NET\Framework(64)\v4.0.30319
aspnet_regiis -ir