0

In an object I am serializing to a document database I have a dynamic property that needs all string values written in lower-case for indexing purposes. I tried using a custom converter for this, but that requires me to write serialization code for several different types. All I want is the standard serialization behavior, but with the string values forced to lower-case. Given the flexibility of the Newtonsoft library this seems like it should be straightforward, I just haven't found the right interface.

Note that I don't have direct control over serialization. I am writing to Azure COSMOSDB, and their client library uses JSON.Net for serialization. I am able to pass in a custom serializer to use.

Update

The following appears to work. Steps are:

  1. add code to populate the dynamic property via JToken.FromObject()
  2. use code below to force all string values to lower-case (arrays were tricky)
  3. send object to CosmosDB

    private static JToken JTokenStringValuesToLower(JToken startToken)
    {
        Stack<JEnumerable<JToken>> tokenStack = new Stack<JEnumerable<JToken>>();
        tokenStack.Push(startToken.Children());
    
        while (tokenStack.Count != 0)
        {
            JEnumerable<JToken> children = tokenStack.Pop();
    
            foreach (JToken child in children)
            {
                if (child.Type == JTokenType.Property)
                {
                    JProperty property = (JProperty)child;
    
                    if (child.HasValues)
                    {
                        tokenStack.Push(child.Children());
                    }
    
                    if (property.Value.Type == JTokenType.String)
                    {
                        property.Value = property.Value.ToString().ToLowerInvariant();
                    }
                }
                else if (child.Type == JTokenType.Array && child.HasValues)
                {
                    JArray array = (JArray)child;
                    JToken[] arrayItems = new JToken[array.Count];
                    int idx = 0;
                    bool modified = false;
    
                    foreach (JToken arrayItem in array.Children())
                    {
                        arrayItems[idx++] = arrayItem;
                    }
    
                    for (int i = 0; i < arrayItems.Length; ++i)
                    {
                        JToken token = arrayItems[i];
    
                        if (token.Type == JTokenType.String)
                        {
                            modified = true;
                            arrayItems[i] = token.ToString().ToLowerInvariant();
                        }
                    }
    
                    if (modified)
                    {
                        array.Clear();
    
                        foreach (JToken item in arrayItems)
                        {
                            array.Add(item);
                        }
                    }
                }
                else if (child.HasValues)
                {
                    tokenStack.Push(child.Children());
                }
            }
        }
    
        return startToken;
    }
    
4
  • Do you mean, field names or field values? Commented Aug 25, 2017 at 16:50
  • stackoverflow.com/questions/2789593/… Commented Aug 25, 2017 at 16:51
  • Values. I edited the question. Commented Aug 25, 2017 at 17:08
  • Since it's the values that you want forced to lowercase I don't think this is a job for JSON.net or any Json serialiser. Can't you simply pass all of the values through a conversion function before saving to CosmosDB? Or if you know they're all strings can't you just say someDynamicObject.someProperty.ToString().ToLower() on each of the fields? Commented Aug 25, 2017 at 17:34

1 Answer 1

0

For a similar question, I found the use of JToken very powerful, as this example (SO) shows how to iterate through a JSON data structure and manipulate each data node based on type or content.

Sign up to request clarification or add additional context in comments.

1 Comment

I think this would work if I had control over serialization. I edited my question to note that I am using Azure CosmosDB, and their client library handles serialization. I can pass in a serializer, but not the serialized string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.