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:
- add code to populate the dynamic property via JToken.FromObject()
- use code below to force all string values to lower-case (arrays were tricky)
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; }