JSON and XML to C# classes in Visual Studio

Although this feature is available for years in Visual Studio, I only recently discovered this gem that allows rapid generation of C# classes from either JSON or XML.

Here is how it works:

  1. Copy the JSON or XML code to the clipboard.
  2. In Visual Studio, go to Edit > Past Special and chose either Paste JSON as classes or Paste XML as classes.

However, this feature is only available if you have the ASP.NET and web development workload installed.

JSON to classes

To check how this feature works and how it compares with other alternatives I picked a couple random JSON examples. The first one is from the responses of the Translator Text API (that you can find here):

[
    {
        "translations":[
            {"text":"你好, 你叫什么名字?","to":"zh-Hans"},
            {"text":"Hallo, was ist dein Name?","to":"de"}
        ]
    }
]

Special pasting in Visual Studio produces the following classes:

public class Rootobject
{
   public Class1[] Property1 { get; set; }
}

public class Class1
{
   public Detectedlanguage detectedLanguage { get; set; }
   public Translation[] translations { get; set; }
}

public class Detectedlanguage
{
   public string language { get; set; }
   public float score { get; set; }
}

public class Translation
{
   public string text { get; set; }
   public Transliteration transliteration { get; set; }
   public string to { get; set; }
}

public class Transliteration
{
   public string script { get; set; }
   public string text { get; set; }
}

A couple of remarks related to this:

  • The Rootobject is not actually present in JSON, and you cannot deserialized the sample JSON to an instance of this class, but rather to a Class1[].
  • The score is a floating point number and the type used here is float, although I would have expected double.

I compared this result with the output of several online similar utilities.

JSON Utils produces the following result:

namespace JSONUtils
{
   public class DetectedLanguage
   {
      public string language { get; set; }
      public double score { get; set; }
   }

   public class Transliteration
   {
      public string script { get; set; }
      public string text { get; set; }
   }

   public class Translation
   {
      public string text { get; set; }
      public Transliteration transliteration { get; set; }
      public string to { get; set; }
   }

   public class TextResponse
   {
      public DetectedLanguage detectedLanguage { get; set; }
      public IList<Translation> translations { get; set; }
   }
}

QuickType has the following result:

namespace QuickType
{
   public partial class TextResponse
   {
      public DetectedLanguage DetectedLanguage { get; set; }
      public Translation[] Translations { get; set; }
   }

   public partial class DetectedLanguage
   {
      public string Language { get; set; }
      public long Score { get; set; }
   }

   public partial class Translation
   {
      public string Text { get; set; }
      public Transliteration Transliteration { get; set; }
      public string To { get; set; }
   }

   public partial class Transliteration
   {
      public string Script { get; set; }
      public string Text { get; set; }
   }
}

Notice that, unlike the Visual Studio functionality where all the options are hard-coded, these online utilies allow you to set various options such as whether property attributes should be generated, whether to use T[] or List<T> and others. The QuickType app supports a larger number of features, although you must be authenticated to toggle them.

The results from these are pretty similar. Neither of them generated a root object like Visual Studio did. The first application used double for the numerical type of 1.0, while the second used long. When I changed the value from 1.0 to 1.2, QuickType also used double.

Another example that I tried was from https://json.org/example.html:

{"widget": {
    "debug": "on",
    "window": {
        "title": "Sample Konfabulator Widget",
        "name": "main_window",
        "width": 500,
        "height": 500
    },
    "image": { 
        "src": "Images/Sun.png",
        "name": "sun1",
        "hOffset": 250,
        "vOffset": 250,
        "alignment": "center"
    },
    "text": {
        "data": "Click Here",
        "size": 36,
        "style": "bold",
        "name": "text1",
        "hOffset": 250,
        "vOffset": 100,
        "alignment": "center",
        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
    }
}} 

The result of converting this to classes was mostly identical in all three cases (Visual Studio, JSON Utils, and QuickType), with the exeption of the casing and the type for the numerical values (QuickType used long instead of int).

public class Rootobject
{
   public Widget widget { get; set; }
}

public class Widget
{
   public string debug { get; set; }
   public Window window { get; set; }
   public Image image { get; set; }
   public Text text { get; set; }
}

public class Window
{
   public string title { get; set; }
   public string name { get; set; }
   public int width { get; set; }
   public int height { get; set; }
}

public class Image
{
   public string src { get; set; }
   public string name { get; set; }
   public int hOffset { get; set; }
   public int vOffset { get; set; }
   public string alignment { get; set; }
}

public class Text
{
   public string data { get; set; }
   public int size { get; set; }
   public string style { get; set; }
   public string name { get; set; }
   public int hOffset { get; set; }
   public int vOffset { get; set; }
   public string alignment { get; set; }
   public string onMouseUp { get; set; }
}

XML to classes

For testing the XML to classes functionalities I used the XML equivalent of the last JSON example, which looks as follows:

<widget>
    <debug>on</debug>
    <window title="Sample Konfabulator Widget">
        <name>main_window</name>
        <width>500</width>
        <height>500</height>
    </window>
    <image src="Images/Sun.png" name="sun1">
        <hOffset>250</hOffset>
        <vOffset>250</vOffset>
        <alignment>center</alignment>
    </image>
    <text data="Click Here" size="36" style="bold">
        <name>text1</name>
        <hOffset>250</hOffset>
        <vOffset>100</vOffset>
        <alignment>center</alignment>
        <onMouseUp>
            sun1.opacity = (sun1.opacity / 100) * 90;
        </onMouseUp>
    </text>
</widget>

Visual Studio converted this to the following C# code:

// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public partial class widget
{

   private string debugField;

   private widgetWindow windowField;

   private widgetImage imageField;

   private widgetText textField;

   /// <remarks/>
   public string debug
   {
      get
      {
         return this.debugField;
      }
      set
      {
         this.debugField = value;
      }
   }

   /// <remarks/>
   public widgetWindow window
   {
      get
      {
         return this.windowField;
      }
      set
      {
         this.windowField = value;
      }
   }

   /// <remarks/>
   public widgetImage image
   {
      get
      {
         return this.imageField;
      }
      set
      {
         this.imageField = value;
      }
   }

   /// <remarks/>
   public widgetText text
   {
      get
      {
         return this.textField;
      }
      set
      {
         this.textField = value;
      }
   }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class widgetWindow
{

   private string nameField;

   private ushort widthField;

   private ushort heightField;

   private string titleField;

   /// <remarks/>
   public string name
   {
      get
      {
         return this.nameField;
      }
      set
      {
         this.nameField = value;
      }
   }

   /// <remarks/>
   public ushort width
   {
      get
      {
         return this.widthField;
      }
      set
      {
         this.widthField = value;
      }
   }

   /// <remarks/>
   public ushort height
   {
      get
      {
         return this.heightField;
      }
      set
      {
         this.heightField = value;
      }
   }

   /// <remarks/>
   [System.Xml.Serialization.XmlAttributeAttribute()]
   public string title
   {
      get
      {
         return this.titleField;
      }
      set
      {
         this.titleField = value;
      }
   }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class widgetImage
{

   private byte hOffsetField;

   private byte vOffsetField;

   private string alignmentField;

   private string srcField;

   private string nameField;

   /// <remarks/>
   public byte hOffset
   {
      get
      {
         return this.hOffsetField;
      }
      set
      {
         this.hOffsetField = value;
      }
   }

   /// <remarks/>
   public byte vOffset
   {
      get
      {
         return this.vOffsetField;
      }
      set
      {
         this.vOffsetField = value;
      }
   }

   /// <remarks/>
   public string alignment
   {
      get
      {
         return this.alignmentField;
      }
      set
      {
         this.alignmentField = value;
      }
   }

   /// <remarks/>
   [System.Xml.Serialization.XmlAttributeAttribute()]
   public string src
   {
      get
      {
         return this.srcField;
      }
      set
      {
         this.srcField = value;
      }
   }

   /// <remarks/>
   [System.Xml.Serialization.XmlAttributeAttribute()]
   public string name
   {
      get
      {
         return this.nameField;
      }
      set
      {
         this.nameField = value;
      }
   }
}

/// <remarks/>
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class widgetText
{

   private string nameField;

   private byte hOffsetField;

   private byte vOffsetField;

   private string alignmentField;

   private string onMouseUpField;

   private string dataField;

   private byte sizeField;

   private string styleField;

   /// <remarks/>
   public string name
   {
      get
      {
         return this.nameField;
      }
      set
      {
         this.nameField = value;
      }
   }

   /// <remarks/>
   public byte hOffset
   {
      get
      {
         return this.hOffsetField;
      }
      set
      {
         this.hOffsetField = value;
      }
   }

   /// <remarks/>
   public byte vOffset
   {
      get
      {
         return this.vOffsetField;
      }
      set
      {
         this.vOffsetField = value;
      }
   }

   /// <remarks/>
   public string alignment
   {
      get
      {
         return this.alignmentField;
      }
      set
      {
         this.alignmentField = value;
      }
   }

   /// <remarks/>
   public string onMouseUp
   {
      get
      {
         return this.onMouseUpField;
      }
      set
      {
         this.onMouseUpField = value;
      }
   }

   /// <remarks/>
   [System.Xml.Serialization.XmlAttributeAttribute()]
   public string data
   {
      get
      {
         return this.dataField;
      }
      set
      {
         this.dataField = value;
      }
   }

   /// <remarks/>
   [System.Xml.Serialization.XmlAttributeAttribute()]
   public byte size
   {
      get
      {
         return this.sizeField;
      }
      set
      {
         this.sizeField = value;
      }
   }

   /// <remarks/>
   [System.Xml.Serialization.XmlAttributeAttribute()]
   public string style
   {
      get
      {
         return this.styleField;
      }
      set
      {
         this.styleField = value;
      }
   }
}

By contrast, the online utility at https://xmltocsharp.azurewebsites.net/ produces the following output from the same XML document:

   /* 
    Licensed under the Apache License, Version 2.0
    
    http://www.apache.org/licenses/LICENSE-2.0
    */
using System;
using System.Xml.Serialization;
using System.Collections.Generic;
namespace Xml2CSharp
{
	[XmlRoot(ElementName="window")]
	public class Window {
		[XmlElement(ElementName="name")]
		public string Name { get; set; }
		[XmlElement(ElementName="width")]
		public string Width { get; set; }
		[XmlElement(ElementName="height")]
		public string Height { get; set; }
		[XmlAttribute(AttributeName="title")]
		public string Title { get; set; }
	}

	[XmlRoot(ElementName="image")]
	public class Image {
		[XmlElement(ElementName="hOffset")]
		public string HOffset { get; set; }
		[XmlElement(ElementName="vOffset")]
		public string VOffset { get; set; }
		[XmlElement(ElementName="alignment")]
		public string Alignment { get; set; }
		[XmlAttribute(AttributeName="src")]
		public string Src { get; set; }
		[XmlAttribute(AttributeName="name")]
		public string Name { get; set; }
	}

	[XmlRoot(ElementName="text")]
	public class Text {
		[XmlElement(ElementName="name")]
		public string Name { get; set; }
		[XmlElement(ElementName="hOffset")]
		public string HOffset { get; set; }
		[XmlElement(ElementName="vOffset")]
		public string VOffset { get; set; }
		[XmlElement(ElementName="alignment")]
		public string Alignment { get; set; }
		[XmlElement(ElementName="onMouseUp")]
		public string OnMouseUp { get; set; }
		[XmlAttribute(AttributeName="data")]
		public string Data { get; set; }
		[XmlAttribute(AttributeName="size")]
		public string Size { get; set; }
		[XmlAttribute(AttributeName="style")]
		public string Style { get; set; }
	}

	[XmlRoot(ElementName="widget")]
	public class Widget {
		[XmlElement(ElementName="debug")]
		public string Debug { get; set; }
		[XmlElement(ElementName="window")]
		public Window Window { get; set; }
		[XmlElement(ElementName="image")]
		public Image Image { get; set; }
		[XmlElement(ElementName="text")]
		public Text Text { get; set; }
	}
}

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.