5
votes

I have the following DTO:

public class MyDTO
{
    public int Id { get; set; }

    public String Info { get; set; }
}

The Info element contains some serialized JSON object which can be of multiple different types. In my service function, I return this DTO using return x.ConvertTo<MyDTO>()

My problem is, that, since ServiceStack is not aware that Info holds a JSON, the special characters (quotation marks) of Info are escaped.

So I get

{"Id":15,"Info":"[\"Test1\",\"Test2\",\"Test3\"]"}

from the service, but what I would like to get is actually

{"Id":15,"Info":["Test1","Test2","Test3"]}

Is there some way, to tell ServiceStack that Info holds JSON data and thus prevent it from escaping the string and instead inserting the JSON value directly into the response?

P.S.: My question is not a duplicate of that question, which is concerned with forcing the default DTO encoding of a service to JSON, while my problem deals with how the JSON encoding happens for certain types.

2
Possible duplicate of ServiceStack default format - Pranav Patel
@PranavPatel My question is not a duplicate of that question. It is concerned with forcing the default DTO encoding of a service to JSON, while my problem deals with how the JSON encoding happens for certain types. - mat
@mat what is expected is not valid JSON. This is not valid JSON {"Id":15,"Info":"{["Test1","Test2","Test3"]}"}. What you actually get is correct as Info is a string so thus it is escaped. - Nkosi
@Nkosi That won't work. Info can basically be encoded from any type. The decoding and interpretation of the values are done solely in the frontend. - mat

2 Answers

2
votes

using composition you can interpret the Info property of MyDTO

public class MyDTO<T> : MyDTO {

    public MyDTO(MyDTO dto) {
        this.Id = dto.Id;
        this.Info = JsonConvert.DeserializeObject<T>(dto.Info);
    }

    public new T Info { get; set; }
}

that way the JSON value in Info can be normalized before returning it to be serialized.

For example

var dto = x.ConvertTo<MyDTO>();
return new MyDTO<dynamic>(dto);

If dto.Info was a JSON array of strings would allow the array to be serialized as desired in the OP

var dto = new MyDTO {
    Id = 15,
    Info = "[\"Test1\",\"Test2\",\"Test3\"]"
}

would produce

{"Id":15,"Info":"[\"Test1\",\"Test2\",\"Test3\"]"}

where as

new MyDTO<dynamic>(dto);

would produce

{"Id":15,"Info":["Test1","Test2","Test3"]}
2
votes

My co-workers and I faced a similar problem, and with the help of Demis Bellot we were able to arrive at a solution that, if translated to the code in the OP, would look like this:

public class MyDTO
{
    public int Id { get; set; }

    public Dictionary<string, object> Info { get; set; }
}

When we populate the DTO, we use JSON.parse like this:

var json = (Dictionary<string, object>)JSON.parse(rawJsonString);
return new MyDTO
{
    Id = 42,
    Info = json
};

Our raw JSON string was a JSON object. In the OP, it looks like the raw JSON string may, instead, be an array, in which case it looks as though the appropriate property type might be List<object>.

JSON.parse can be found in ServiceStack.Common.