Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Newton CamelCase Issue with underscore

Tags:

c#

json.net

I've notice that when I serialize C# dictionary which has key of HTTP_VERB it turn into httP_VERB in the JSON structure instead of hTTP_VERB or http_verb I expected the camel case will make it.

This is the code I use to reproduce the issue:

  class Program {
    static void Main(string[] args) {

      var settings = new JsonSerializerSettings();

      settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
      settings.NullValueHandling = NullValueHandling.Ignore;

      var headers = new Dictionary<string, string>();
      headers["SessionID"] = "123456";
      headers["HTTP_VERB"] = "POST";
      headers["HTTPVERSION"] = "1";
      var data = new
      {
        headers = headers
      };

      string serializedEvent = JsonConvert.SerializeObject(data, settings);

      if (serializedEvent.Contains("httP_VERB")) {
        Console.WriteLine("Something is wrong with this camel case");
      }
      else {
        Console.WriteLine("Sucess");
      }

    }
  }
like image 299
Ido Ran Avatar asked Sep 16 '13 07:09

Ido Ran


People also ask

What is CamelCase example?

/ˈkæm. əl ˌkeɪs/ the use of a capital letter to begin the second word in a compound name or phrase, when it is not separated from the first word by a space: Examples of camel case include "iPod" and "GaGa".

What is Camelcasepropertconamescontractresolver?

CamelCasePropertyNamesContractResolver Class. Resolves member mappings for a type, camel casing property names.

What is JsonSerializerSettings?

Specifies the settings on a JsonSerializer object.

What is Jsonconvert SerializeObject C#?

SerializeObject Method (Object, Type, JsonSerializerSettings) Serializes the specified object to a JSON string using a type, formatting and JsonSerializerSettings. Namespace: Newtonsoft.Json.


1 Answers

There's no way to make CamelCasePropertyNamesContractResolver convert strings to camel case the way you want, but you can easily write your own ContractResolver.

I've used PascalCase conversion in my CsCss project. After a bit of adaptation, here's the result:

public enum IdentifierCase
{
    Camel,
    Pascal,
}

public class CustomPropertyNamesContractResolver : DefaultContractResolver
{
    private static readonly CultureInfo Culture = CultureInfo.InvariantCulture;

    public CustomPropertyNamesContractResolver (bool shareCache = false)
        : base(shareCache)
    {
        Case = IdentifierCase.Camel;
        PreserveUnderscores = true;
    }

    public IdentifierCase Case { get; set; }
    public bool PreserveUnderscores { get; set; }

    protected override string ResolvePropertyName (string propertyName)
    {
        return ChangeCase(propertyName);
    }

    private string ChangeCase (string s)
    {
        var sb = new StringBuilder(s.Length);

        bool isNextUpper = Case == IdentifierCase.Pascal, isPrevLower = false;
        foreach (var c in s) {
            if (c == '_') {
                if (PreserveUnderscores)
                    sb.Append(c);
                isNextUpper = true;
            }
            else {
                sb.Append(isNextUpper ? char.ToUpper(c, Culture) : isPrevLower ? c : char.ToLower(c, Culture));
                isNextUpper = false;
                isPrevLower = char.IsLower(c);
            }
        }
        return sb.ToString();
    }

    // Json.NET implementation for reference
    private static string ToCamelCase (string s)
    {
        if (string.IsNullOrEmpty(s) || !char.IsUpper(s[0]))
            return s;
        var sb = new StringBuilder();
        for (int i = 0; i < s.Length; ++i) {
            if (i == 0 || i + 1 >= s.Length || char.IsUpper(s[i + 1]))
                sb.Append(char.ToLower(s[i], Culture));
            else {
                sb.Append(s.Substring(i));
                break;
            }
        }
        return sb.ToString();
    }
}

This converter supports both PascalCase and camelCase. It seems to convert the property names the way you expect.

I've left oroginal ToCamelCase function from Json.NET for reference.

Sample program:

internal class Program
{
    private static void Main ()
    {
        var obj = new Dictionary<string, string> {
            { "SessionID", "123456" },
            { "HTTP_VERB", "POST" },
            { "HTTPVERSION", "1" },
        };
        var settings = new JsonSerializerSettings {
            Formatting = Formatting.Indented,
            ContractResolver = new CustomPropertyNamesContractResolver()
        };
        string strCamel = JsonConvert.SerializeObject(obj, settings);
        Console.WriteLine("camelCase: \n" + strCamel);
        Console.WriteLine(strCamel.Contains("httP_VERB") ? "Something is wrong with this camel case" : "Success");
        settings.ContractResolver = new CustomPropertyNamesContractResolver {
            Case = IdentifierCase.Pascal,
            PreserveUnderscores = false,
        };
        string strPascal = JsonConvert.SerializeObject(obj, settings);
        Console.WriteLine("PascalCase: \n" + strPascal);
        Console.ReadKey();
    }
}

Output:

camelCase:
{
  "sessionId": "123456",
  "http_Verb": "POST",
  "httpversion": "1"
}
Success
PascalCase:
{
  "SessionId": "123456",
  "HttpVerb": "POST",
  "Httpversion": "1"
}
like image 124
Athari Avatar answered Oct 03 '22 16:10

Athari