How to serialize a Lookup<string, string> object into JSON?

As a workaround to creating a custom converter, you could convert your Lookup<TKey, TElement> into a Dictionary<TKey, List<TElement>> which Newtonsoft.Json plays nice with.

myLookup.ToDictionary(x => x.Key, x => x.ToList());

You're right in that Newtonsoft.Json doesn't treat Lookup<TKey, TElement> nicely. The following code:

var input = new List<string>()
{
    "A1",
    "A2",
    "B1",
    "C1",
    "C2"
};

var lookup = input.ToLookup(i => i[0], i => i);
var json = JsonConvert.SerializeObject(lookup);

Console.WriteLine(json);        

Serializes as:

[["A1","A2"],["B1"],["C1","C2"]]

You correctly notice the key names (A, B, C) are missing, it appears to be serialized as an array of arrays.

There appears to be no support for serializing a lookup out of the box, so you'll have to write your own converter.

I found one here, but that requires you to know the type of key and value on beforehand.

Modified it, this does the job:

        // Same as above, up till here
        var json = JsonConvert.SerializeObject(lookup, new LookupSerializer());
        Console.WriteLine(json);
    }
}

public class LookupSerializer : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        var result = objectType.GetInterfaces().Any(a => a.IsGenericType 
            && a.GetGenericTypeDefinition() == typeof(ILookup<,>));
        return result;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var obj = new JObject();            
        var enumerable = (IEnumerable)value;

        foreach (object kvp in enumerable)
        {
            // TODO: caching
            var keyProp = kvp.GetType().GetProperty("Key");
            var keyValue = keyProp.GetValue(kvp, null);

            obj.Add(keyValue.ToString(), JArray.FromObject((IEnumerable)kvp));
        }

        obj.WriteTo(writer);
    }
}

Output:

{
    "A": ["A1", "A2"],
    "B": ["B1"],
    "C": ["C1", "C2"]
}