0

Let's say I have a JSON based string that looks: {"Hello":"1"} I want to convert it to look like {"HELLO":"1"}.

I have created an upper case naming strategy:

public class UpperCaseNamingStrategy : NamingStrategy
{
  protected override string ResolvePropertyName(string name)
  {
    return name.ToUpper();
  }
}

Which works when manipulating an object:

[Fact]
public void TestUpperCase()
{
    var thing = new {Hello = "1"};

    var jsonSerializerSettings = new JsonSerializerSettings
    {
        ContractResolver = new DefaultContractResolver
        {
            NamingStrategy = new UpperCaseNamingStrategy { OverrideSpecifiedNames = true }
        }
    };
    var serializeObject = JsonConvert.SerializeObject(thing, jsonSerializerSettings);
    Assert.Equal("{\"HELLO\":\"1\"}", serializeObject); // Works fine
}

But when I load in a string via the JObject.Parse API, it seems to leave the string as is:

[Fact]
public void TestUpperCase2()
{
    var thing = JObject.Parse("{\"Hello\":\"1\"}");

    var jsonSerializerSettings = new JsonSerializerSettings
    {
        ContractResolver = new DefaultContractResolver
        {
            NamingStrategy = new UpperCaseNamingStrategy { OverrideSpecifiedNames = true }
        }
    };
    var serializeObject = JsonConvert.SerializeObject(thing, jsonSerializerSettings);
    Assert.Equal("{\"HELLO\":\"1\"}", serializeObject); // this fails Actual:   {"Hello":"1"}
}

In this test I am simulating my use case, I am retrieving a JSON response from a REST API, I am trying to take that response string and convert all of the keys into upper case string.

Doing a little debugging I can see that the object that is getting loaded into the JObject looks something like {{"Hello": "1"}}.

I just want to point out that the data I am using is much more complex than just simple "hello" I just wanted a quick example, let's say I have 20 fields some being objects some being arrays, is there an easy way I can parse the JSON and have all the keys to use upper case naming.

Mark Davies
  • 1,447
  • 1
  • 15
  • 30
  • What's the use case for requiring uppercase keys? –  Dec 04 '19 at 15:51
  • 1
    @Josh It's to simply make the JSON from one system consistent with another system, I would agree this is probably the "wrong way around" we should probably make it camel case consistent but I'm not in charge here :D – Mark Davies Dec 04 '19 at 15:54
  • 1
    That's why I was asking, because JSON parsers by default are case-insensitive, so I was curious on the requirement. –  Dec 04 '19 at 15:55
  • 2
    Note that in the second instance, you're serializing a `JObject` object to a string. There is no `Hello` property whose name will be capitalized in that scenario. – Heretic Monkey Dec 04 '19 at 16:04
  • @HereticMonkey maybe I should edit this into the post but I am simulating a response from a http call, so in the instance where I am parsing a string into a JObject I was attempting to create an object to send into the JsonConvert method, if you know an alternative method please let me know, so you imagine im calling a rest service getting a json string back and I'm trying to have a jobject with upper case keys – Mark Davies Dec 04 '19 at 16:06
  • 1
    This question and its second answer may help: https://stackoverflow.com/questions/40244395/how-to-serialize-a-jobject-the-same-way-as-an-object-with-json-net – Martin Dec 04 '19 at 16:07
  • @Martin sadly the expando object didn't work – Mark Davies Dec 04 '19 at 16:09
  • 1
    @MarkDavies This one has a related solution that involves `JObject` and camel-casing: https://stackoverflow.com/questions/15087340/jobject-camelcase-conversion-with-json-net – Martin Dec 04 '19 at 16:12
  • I think the whole `UpperCaseNamingStrategy` is throwing me off. If what you want to do is change the names of properties in your JSON, parse it using `JToken.Parse(string)`, then iterate over the `JProperties`, setting their names to whatever you want. Output the resulting `JToken.ToString()`. – Heretic Monkey Dec 04 '19 at 16:15
  • It's an option @HereticMonkey I was wondering if there was a more efficient way – Mark Davies Dec 04 '19 at 16:15
  • For the record, my first thought when I started to read this post was the same as Josh's: I wonder if OP knows that JSON parsers are not case-sensative. If Josh hadn't asked, I would have. – Casey Crookston Dec 04 '19 at 16:21
  • @MarkDavies, a really fast way to get your JSON string to all be the same case type would be to deserialize it to an object, and then serialize it back to a json string. The resulting string would be the same case type as the class it came from. Two lines of code, and done. – Casey Crookston Dec 04 '19 at 16:26
  • @CaseyCrookston And yet the parser in JSON.Net supports casing strategies such as `CamelCasePropertyNamesContractResolver`. – Martin Dec 04 '19 at 16:31
  • 1
    @Martin, right. But from the OP, I was under the impression that there might be some business case where non-conventional casing was required. – Casey Crookston Dec 04 '19 at 16:33
  • 1
    Calling `JsonConvert.SerializeObject(JObject)` basically just calls `JObject.ToString()`. If you know the object structure ahead of time, using a strongly-typed object instead of `JObject` would be the way to go. –  Dec 04 '19 at 16:45

2 Answers2

0

The way I've decided to solve this problem is to create a POCO (plain old c object) to store the information from the API response:

public class Poco 
{
    public string Hello {get;set;}
}

When I want to upper case all of the property keys send it through the serialization with my Upper case naming strategy:

var responseModel = JsonConvert.DeserializeObject<TResponse>(data);
return JObject.Parse(JsonConvert.SerializeObject(responseModel, 
            new  JsonSerializerSettings
            {
                DefaultValueHandling = DefaultValueHandling.Ignore,
                ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = new UpperCaseNamingStrategy
                    {
                        OverrideSpecifiedNames = true
                    }
                }
            }));

I wish there was a more generic way of doing this, but this seems like a sensible solution

Mark Davies
  • 1,447
  • 1
  • 15
  • 30
0

So in case someone still tries to figure that out:

Declare a naming policy

public class UpperCaseNamingPolicy : JsonNamingPolicy
{
    public override string ConvertName(string name) => name.ToUpper();
}

And in your controller:

 using System.Text.Json;

 var options = new JsonSerializerOptions
 {
     PropertyNamingPolicy = new UpperCaseNamingPolicy(),
     WriteIndented = true
 };

 return Json(result, options);
Bumber
  • 59
  • 3