3

In C#, a valid variable name cannot contain dashes. But in Json, all property names are based off of strings, so what would be considered an invalid character for a C# variable name, could be considered valid in Json.

My question is, how does JSON.Net handle having a Dash, or other invalid data inside of a Property name when attempting to deserialize to an Anonymous Type, and more importantly, what do you replace invalid characters with in the Anonymous Type to capture it.

If example data is required, i can provide it but quite frankly just add a Dash (-) to a Json Property name, and you've got my situation in a nutshell.

P.S: I cannot change the Json itself, because it is being consumed from an API.

Nikey646
  • 184
  • 1
  • 11

2 Answers2

2

You can use a ContractResolver to manipulate how JSON.Net maps C# property names to JSON names.

For your example this code does that:

class DashContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
    protected override string ResolvePropertyName(string propertyName)
    {
        // Count capital letters
        int upperCount = propertyName.Skip(1).Count(x => char.IsUpper(x));
        // Create character array for new name
        char[] newName = new char[propertyName.Length + upperCount];
        // Copy over the first character
        newName[0] = char.ToLowerInvariant(propertyName[0]);

        // Fill the character, and an extra dash for every upper letter
        int iChar = 1;
        for (int iProperty = 1; iProperty < propertyName.Length; iProperty++)
        {
            if (char.IsUpper(propertyName[iProperty]))
            {
                // Insert dash and then lower-cased char
                newName[iChar++] = '-';
                newName[iChar++] = char.ToLowerInvariant(propertyName[iProperty]);
            }
            else
                newName[iChar++] = propertyName[iProperty];
        }

        return new string(newName, 0, iChar);
    }
}

class Program
{
    static void Main(string[] args)
    {
        string json = @"{""text-example"":""hello""}";
        var anonymous = new { textExample = "" };
        var obj = JsonConvert.DeserializeAnonymousType(json, anonymous,
            new JsonSerializerSettings
            {
                ContractResolver = new DashContractResolver()
            });


    }
}

It converts UpperCamelCase and lowerCamelCase to lower-dash-case. Therefore mapping to your JSON input.

This overload of DeserializeAnonymousType has not always been available, and isn't available in the version released with Visual Studio 2013. The current (stable) NuGet package has this overload in it.

Aidiakapi
  • 6,034
  • 4
  • 33
  • 62
  • This does appear to be what i want, but i will need to wrap my head around your logic within the For Loop, i don't quite understand what it is doing... – Nikey646 Mar 01 '15 at 00:13
  • I have no idea why your ContractResolver is adding additional dashes into the property name, but the magic is working and is exactly what i want! Edit: After outputting the newName and the propertyName, i realized i was looking at this backwards. It's taking the name i want and converting it to the JSON name it should be looking for. – Nikey646 Mar 01 '15 at 00:28
  • @Nikey646 Yeah that's the way JSON.Net works, takes your object, then finds the properties to match it to. It just fills a new slightly bigger array (to fit the dashes) with the old characters and the occasional dash. It doesn't test for 0 zero length or null strings (it's incapable of handling those) but I kind of assumed that JSON.Net will never pass these to you, since you cannot have 0-length or null variable names in C#. (And I'm pretty sure in .NET in general.) – Aidiakapi Mar 01 '15 at 00:36
1

I'd suggest looking at the Dynamic rather than Anonymous UI for Json.Net, which can deserialise your data to ExpandoObject, which is a dynamic type that behaves like a dictionary - i.e. similar to a JavaScript object. This will then mean the range of allowed property names goes up, because they become dictionary keys rather than .Net properties.

Kind of like: Deserialize a property as an ExpandoObject using JSON.NET

Community
  • 1
  • 1
RichardW1001
  • 1,985
  • 13
  • 22
  • I'm actually moving away from Dynamic objects, due to troubles related to using Arrays and having to re-serialize to return an object from the Dynamic Object. – Nikey646 Mar 01 '15 at 00:10