cvsguimaraes
cvsguimaraes

Reputation: 13230

Service Stack response DTO with specific data inside JSON arrays

I'm modeling my response DTOs for services which returns JSON data like this:

{
    "response":
    {
        "metadataA" : "useless info a",
        "metadataB" : "useless info b",
        "metadataC" : "useless info c",
        ...
        "metadataZ" : "useless info z",
        "results" :
        [
            {
                "resultmetadataA" : "useless info a",
                "resultmetadataB" : "useless info b",
                "resultId": "a",
                "resultName": "A"
            },
            {
                "resultmetadataA" : "useless info a",
                "resultmetadataB" : "useless info b",
                "resultId": "b",
                "resultName": "B"
            }

        ]
    }
}

Obviously, I just want my DTO to have a list of results with ids and names like this:

class Response
{
    public List<Result> Results { get; set; }
}

class Result
{
    public string Id  { get; set; }
    public string Name  { get; set; }
}

Is there some property attribute to tell Service Stack the "path" for id and name values?


Edit 1

I'm trying to use some attributes from ServiceStack.DataAnnotations with no luck. Tried to use CompositeIndex(false, "response", "results") in Results and Alias in Results properties, but Results keep coming null.

Help please!

Edit 2

Also tried [DataContract] in Response and [DataMember(Name = Id/Name)] on properties to parse those data directly, but it doesn't seem to work.

Upvotes: 2

Views: 1961

Answers (3)

cvsguimaraes
cvsguimaraes

Reputation: 13230

Afterall I've found no way to model simple DTOs for complex responses, thanks for all answers anyway.

Well, it's really sad my POCO's structure being dependent of the JSON response structure. However, I can abstract the response structure and make all my DTOs deal with it at once.

Considering a similar JSON structure from my question:

{
    "response":
    {
        ...,
        "results":
        [
            {
                "resourceType": "letter" ,
                "resources": ["a", "b", "c", ...]
            },
            {
                "resourceType": "number" ,
                "resources": ["1", "2", "3", ...]
            },
            ...
        ]    
    }
}

I abstracted the commom response structure:

enum ResourceKind
{
    Letter,
    Number
}

public class BaseResponse
{
    public ResponseContent Response
    {
        get;
        set;
    }
}

public class ResponseContent
{
    public List<ResultContent> Results
    {
        get;
        set;
    }
}

public class ResultContent
{
    public ResourceKind Kind
    {
        get;
        set;
    }

    public List<string> Resources
    {
        get;
        set;
    }
}

And finally got a simplified implementation for one (of dozens) specific server response:

public class SpecificResponse : BaseResponse
{
    public IEnumerable<SpecificResult> Results
    {
        get
        {
            foreach(ResultContent result in Response.Results)
            {
                SpecificResult newSpecificResult = new SpecificResult();
                newSpecificResult.Kind = result.Kind;
                newSpecificResult.Resources = result.Resources;
                yield return newCategory;
            }

            yield break;
        }
    }
}

I still looking for something better, but for now that's my solution.

Upvotes: 0

mythz
mythz

Reputation: 143284

To start with your JSON is invalid "response": [ cannot be an array literal but contain object properties.

How to debug Serialization issues

The goal is for your schema to match the shape of the JSON. Don't try guess what the shape should be, get in the habit of inferring the shape, trying it out see what properties get serialized. If no properties are getting serialized do the reverse and populate and serialize your POCOs to see what shape they're expected to be in then compare the shapes to the original JSON to see where they differ. See this answer for other tips on debugging serialization issues.

var json = @"{
    ""response"":
    {
        ""metadataA"" : ""useless info a"",
        ""metadataB"" : ""useless info b"",
        ""metadataC"" : ""useless info c"",
        ""metadataZ"" : ""useless info z"",
        ""results"" :
        [
            {
                ""resultmetadataA"" : ""useless info a"",
                ""resultmetadataB"" : ""useless info b"",
                ""resultId"": ""a"",
                ""resultName"": ""A""
            },
            {
                ""resultmetadataA"" : ""useless info a"",
                ""resultmetadataB"" : ""useless info b"",
                ""resultId"": ""b"",
                ""resultName"": ""B""
            }

        ]
    }
}";

Inferred types from the above JSON:

public class MetadataResponse
{
    public Response Response { get; set; }
}

public class Response
{
    public string MetadataA { get; set; }
    public string MetadataB { get; set; }
    public string MetadataC { get; set; }
    public string MetadataZ { get; set; }
    public List<Result> Results { get; set; }
}

public class Result
{
    public string ResultmetadataA { get; set; }
    public string ResultmetadataB { get; set; }
    public string ResultId { get; set; }
    public string ResultName { get; set; }
}

Testing the JSON serialization using above types:

var dto = json.FromJson<MetadataResponse>();
dto.PrintDump();

Output:

{
    Response: 
    {
        MetadataA: useless info a,
        MetadataB: useless info b,
        MetadataC: useless info c,
        MetadataZ: useless info z,
        Results: 
        [
            {
                ResultmetadataA: useless info a,
                ResultmetadataB: useless info b,
                ResultId: a,
                ResultName: A
            },
            {
                ResultmetadataA: useless info a,
                ResultmetadataB: useless info b,
                ResultId: b,
                ResultName: B
            }
        ]
    }
}

Upvotes: 1

Darin Dimitrov
Darin Dimitrov

Reputation: 1038710

You could use a dictionary:

public class ResponseDTO
{
    public List<Dictionary<string, string>> Results { get; set; }
}

Upvotes: 3

Related Questions