Question

Given a set of static, nested classes such as this:

public static class LocalSiteMap
{
    public static class Navigation
    {
        public static readonly string Home = "homePage";

        public static class PageIds
        {
            public static class ShowManagement
            {
                public static readonly string Index = "showManagement";
            }

            public static class Shows
            { 
                public static readonly string Create = "addShows";
            }
        }

        public static class Actors
        {
            public static readonly string Details = "actorDetailsForm";
            public static readonly string History= "historyDetailsForm";
        }
    }
}

I would like to build an equivalent JSON string, such as this:

{ 'localSiteMap' : {
    { 'navigation': {
        'home': 'homePage',
        'pageIds': {
            'showManagement': {
                'index': 'showManagement'
            },
            'shows': {
                'create': 'addShows'
            }
        },
        'actors': {
            'details': 'actorDetailsForm',
            'history': 'historyDetailsForm'
        }
    }
}

Each nested class results in a nested object in the JSON. Each string property results in a string Key/Value pair in the JSON.

I know I can reflect over the root Static Class and build a JSON string pretty easily (and that's the approach I'm currently taking), but I wondered if there was a more elegant way to do it. For example, if this were an instance anonymous type then I could serialise it pretty easily.

Some background: this is a set of constants to be passed via a WebAPI Controller to a Single Page Application running in a browser. Having the same set of page identifiers available in both C# (Server) and JS (Client) worlds is very useful for browser automation tests which use the Page Object pattern.

The 'LocalSiteMap' static class is already baked in to a fairly mature project, so changing it to a instance classes or an anonymous type instead isn't really an option for me.

Was it helpful?

Solution

The issue with building a string here is you have to ensure that the syntax is 100% correct, opening and closing braces, adding commas etc. All possible but quite a hassle.

A solution to avoid magic strings altogether is to use LINQ-to-XML as an intermediary translation step. Like this:

public static class NestedStaticClassWithStringPropertiesJsoniser
{
    public static string GetJson(this Type type)
    {
        XElement rootXml = new XElement(type.Name);
        XElement xmlContent = CreateXmlTree(rootXml, type);

        string jsonString = JsonConvert.SerializeXNode(xmlContent);

        return jsonString;
    }

    public static XElement CreateXmlTree(XElement parent, Type type)
    {
        AddStringProperties(parent, type);

        AddNestedClasses(parent, type);

        return parent;
    }

    private static void AddNestedClasses(XElement parent, Type type)
    {
        var subTypes = type.GetNestedTypes();

        foreach (var subType in subTypes)
        {
            var newElement = new XElement(subType.Name);
            var subTree = CreateXmlTree(newElement, subType);
            parent.Add(subTree);
        }
    }

    private static void AddStringProperties(XElement parent, Type type)
    {
        var properties = type.GetFields();
        foreach (var property in properties)
        {
            var propertyElement = new XElement(property.Name);
            propertyElement.SetValue(property.GetValue(null));
            parent.Add(propertyElement);
        }
    }
}

It can easily be used like this:

string json = typeof(ATypeWithNestedStaticClasses).GetJson();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top