Restsharp: JSON Serializer doesn't turn C# Dictionary into JSON Object as expected

Created on 27 May 2015  ·  6Comments  ·  Source: restsharp/RestSharp

So I have a method like so:

public static void SomeApiCall(string foo, string bar, Dictionary<String, Dictionary<String, int[]>> list, ...)
{
  var request = new RestRequest("some/endpoint", Method.PUT);
  request.AddJsonBody(new { foo = foo, bar = bar, list = list });
  ...
}

Note the type of list is a Dictionary. This should be directly translated into JSON as an object like {"key1": ..., "key2": ...}, but what I get on the other end is actually [{"Key":"key1","Value": ...}, {"Key":"key2","Value": ...}], which is of course incompatible with what other clients send. The dictionaries inside it have the same issue.

From what I can see, RestSharp is using SimpleJson as its serializer. I tried serializing with Newtonsoft, which produces the expected JSON string. It works great after finding the hacky method to send a string in the body, which seems to be the only way to not have the body serialized by RestSharp internally:

var jout = JObject.FromObject(new { foo = foo, bar = bar, list = list });
request.AddParameter("application/json; charset=utf-8", jout.ToString(Formatting.None), ParameterType.RequestBody);

So yeah, can we get a better default serializer, way to override the serializer, or more elegant method to set a string as the body?

feature-request

Most helpful comment

I solved the problem by manipulating the body parameter directly:

restRequest.AddJsonBody(toBeSerializedContainingDictionary);
var bodyParameter = restRequest.Parameters.First(p => p.Type == ParameterType.RequestBody);
restRequest.Parameters.Remove(bodyParameter);
bodyParameter.Value = JsonConvert.SerializeObject(toBeSerializedContainingDictionary);
restRequest.Parameters.Add(bodyParameter);

All 6 comments

There are plans to switch back to or at least offer the Json.Net library for de/serialization. There are some challenges though that I'm still working through. You can implement a custom de/serializer that uses it in the meantime however. I will also see what I can do about SimpleJson's implementation of dictionaries.

I ran into this problem as well and found a workaround that suits my needs for now.

I used the extension method for a dictionary described here: http://theburningmonk.com/2011/05/idictionarystring-object-to-expandoobject-extension-method/

ExpandoObject eo = mydictionary.ToExpando();

This will convert a Dictionary to a (dynamic) ExpandoObject.
The ExpandoObject is then properly serialized in the format: {"key1": ..., "key2": ...}

In my case I had a Dictionary> so I had to first convert it to Dictionary

I hope this can be useful for others running into this issue.

I solved the problem by manipulating the body parameter directly:

restRequest.AddJsonBody(toBeSerializedContainingDictionary);
var bodyParameter = restRequest.Parameters.First(p => p.Type == ParameterType.RequestBody);
restRequest.Parameters.Remove(bodyParameter);
bodyParameter.Value = JsonConvert.SerializeObject(toBeSerializedContainingDictionary);
restRequest.Parameters.Add(bodyParameter);

@mathume Thanks...that does the trick

Another workaround is to make an ISerializer to handle this. You can make it generic enough to support an arbitrary DTO, as well.

```C#
///


/// Example DTO, where we have a top-level key whose value is a JSON object
/// with dynamic keys. The value for those keys is some object.
///

public class MyDto
{
///
/// The key that is holding the dynamic data.
///

public Dictionary SomeKey { get; set; } =
new Dictionary();

/// <summary>
/// Helper method to easily add new objects.
/// </summary>
public MyDto AddDynamicObject(string dynamicKey, object obj)
{
    SomeKey[dynamicKey] = obj;
    return this;
}

}

///


/// Serializer used to produce JSON strings from the DTO.
///

public class MyDtoSerializer : ISerializer
{
public string RootElement { get; set; }
public string Namespace { get; set; }
public string DateFormat { get; set; }
public string ContentType { get; set; }

/// <summary>
/// Serialize the object, where obj is assumed to be a MyDto instance.
/// </summary>
public string Serialize(object obj)
{
    return JsonConvert.SerializeObject(obj);
}

}

///


/// Simple extension showing how to add the data to the request.
///

public static IRestRequest AddMyDto(IRestRequest restRequest, MyDto dto)
{
// Change the serializer to use our new serializer
// Note that you may need to set the serializer's ContentType to be "application/json"
request.JsonSerializer = new MyDtoSerializer();

// Add the DTO - behind the scenes it is serialized to a JSON string using our serializer
request.AddJsonBody(dto);
return request;

}

The output JSON will then look something like the following (note - the values are simply placeholders):

```JSON
{
    "SomeKey": {
        "dynamicKey-1": "value-1",
        "dynamicKey-2": "value-2",
        "dyanmicKey-n": "value-n"
    }
}

This will be handled as part of #1018

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Taher-Assad picture Taher-Assad  ·  5Comments

ChenJasonGit picture ChenJasonGit  ·  5Comments

mwinder picture mwinder  ·  7Comments

vDeggial picture vDeggial  ·  6Comments

thomasd3 picture thomasd3  ·  5Comments