Click here to Skip to main content
13,599,052 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

4.6K views
130 downloads
7 bookmarked
Posted 13 Feb 2018
Licenced CPOL

Creating Dynamic Object from XML using ExpandoObject and Put Intellisense using C#

, 14 Feb 2018
Rate this:
Please Sign up or sign in to vote.
Creating dynamic object from XML using ExpandoObject and put Intellisense using C#

Introduction

In my current project, we need to store a lot of constant values to run the system which can be achieved in different ways like using Resource File, Web.config, etc. We want those values to be environment specific (e.g., Development, Stage, QA, Production) and also Intellisense feature to use those values.

Existing approaches have the following limitations:

  • In case of config files, Intellisense feature is not available. Hence, there is always a probability of human error which is very difficult to find out.
  • In our scenario, there are cases where we want collection object to be populated from the constant values which are cumbersome in case of resource file approach used.
  • To enhance maintainability, values used for given context / module should be clubbed together which is difficult to achieve using existing approaches.

While searching for a better way, I found the .NET System.Dynamic.ExpandoObjec class, it will represent an object whose members can be dynamically added and removed at run time. I also found that an ExpandoObject was being used to represent an XML document. That is, while parsing, an ExpandoObject instance is created and each XML element is added as a member of the ExpandoObject. With a little more research, I found "ImpromptuInterface" package in NuGet. With the “ImpromptuInterface", any object can be wrapped with an interface.

So we decided to load the XML data into a dynamic type using the System.Dynamic.ExpandoObjec class.

Using the Code

For example, this XML: Constants.xml

<?xml version="1.0" encoding="utf-8" ?>
<Settings>
  <Config>
    <AppData1>Data1</AppData1>
    <AppData2>Data2</AppData2>
    <SFTP>
      <UserName>TestUser</UserName>
      <Password>TestPwd</PassWord>
      <Port>22</Port>
    </SFTP>
  </Config>
</Settings>

The below line of code loads an XML file from disk.

//
// Load an XML document
//
var xDoc = XDocument.Load(new StreamReader(xmlFileName));
...

The below section creates a list of XML node names that are known to contain lists of items. Once the XML is loaded, creation of the dynamic object can begin by calling Parse() method. Once the parsing is complete, the parsed data may then be used.

//
// Convert the XML document in to a dynamic C# object.
// 
Parse(root, xDoc.Elements().First());
...

Below functions are used to load the XML to dynamic object in C#.

public static dynamic GetConstantsData(string xmlFileName)
{
     dynamic root = new ExpandoObject();
     if (string.IsNullOrEmpty(xmlFileName))
     {
          return root;
     }
     // Load an XML document.
     var xDoc = XDocument.Load(new StreamReader(xmlFileName));

     // Convert the XML document in to a dynamic C# object.
     Parse(root, xDoc.Elements().First());
     return root;
}
...
//
// Parse the XML document
//
private static void Parse(dynamic parent, XElement node)
{
   try
   {
      if (node.HasElements)
      {
         if (node.Elements(node.Elements().First().Name.LocalName).Count() > 1)
         {
            //list
            var item = new ExpandoObject();
            var list = new List<dynamic>();
            foreach (var element in node.Elements())
            {
               Parse(list, element);
            }
            AddProperty(item, node.Elements().First().Name.LocalName, list);
            AddProperty(parent, node.Name.ToString(), item);
         }else{
            var item = new ExpandoObject();
            foreach (var attribute in node.Attributes())
            {
               AddProperty(item, attribute.Name.ToString(), attribute.Value.Trim());
            }
            //element
            foreach (var element in node.Elements())
            {
               Parse(item, element);
            }
            AddProperty(parent, node.Name.ToString(), item);
         }
      }else{
         AddProperty(parent, node.Name.ToString(), node.Value.Trim());
      }
   }
   catch (Exception Ex)
   {
      throw new Exception(Ex.Message);
   }
}
...
private static void AddProperty(dynamic parent, string name, object value)
{
     try
     {
          if (parent is List<dynamic>)
          {
               (parent as List<dynamic>).Add(value);
          }
          else
          {
               (parent as IDictionary<string, object>)[name] = value;
          }
     }
     catch (Exception Ex)
     {
          throw new Exception(Ex.Message);
     }
}
...

Install ImpromptuInterface

Open Package Manages Console Using Visual Studio Click Tools -> NuGet Package Manages -> Package Manages Console. Run the below command:

PM> Install-Package ImpromptuInterface
...

Defining Interfaces

Prior to adding the above dynamic behaviors to objects, we need to make sure the objects have interface methods. The interfaces for the sample XML are defined as follows:

public interface IXML
{
    ISettings Settings { get; }
}

public interface ISettings
{
    IConfig Config { get; }        
}

public interface IConfig
{
    string AppData1 { get; set; }
    string AppData2{ get; set; }
    ISFTP SFTP { get; }        
}

public interface ISFTP
{
    string UserName { get; set; }
    string PassWord { get; set; }
    object Port { get; set; }
}
...

Wrapping Objects and Attaching Behaviors

The extension method ActLike<I> of object can be used to wrap an object with an interface.

//
// To view the output run the below code
//
static void Main(string[] args)
{
    dynamic constantsData = XmlToDynamic.GetConstantsData("Constants.xml");
    IXML xml = ImpromptuInterface.Impromptu.ActLike(constantsData);

    Console.WriteLine("AppData1 = " + xml.Settings.Config.AppData1);
	Console.WriteLine("AppData2 = " + xml.Settings.Config.AppData2);
	Console.WriteLine("UserName = " + xml.Settings.Config.SFTP.UserName);
	Console.WriteLine("PassWord = " + xml.Settings.Config.SFTP.PassWord);
	Console.WriteLine("Port = " + xml.Settings.Config.SFTP.Port);
}

//
// Output
//

...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Apurba pan
Software Developer (Senior)
India India
No Biography provided

You may also be interested in...

Pro
Pro

Comments and Discussions

 
QuestionWhat is the advantage? Pin
Gokhan Mamaci14-Feb-18 22:33
professionalGokhan Mamaci14-Feb-18 22:33 
AnswerRe: What is the advantage? Pin
Vaso Elias19-Feb-18 2:46
memberVaso Elias19-Feb-18 2:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web04 | 2.8.180621.3 | Last Updated 14 Feb 2018
Article Copyright 2018 by Apurba pan
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid