3

Quite new to .NET. Still haven't gotten the hang of how to do dictionaries, lists, arrays, etc.

I need to produce this JSON in order to talk to SugarCRM's REST API:

{
    "name_value_list": {
        "assigned_user_name": {
            "name": "assigned_user_name",
            "value": "joe"
        },
        "modified_by_name": {
            "name": "modified_by_name",
            "value": "jill"
        },
        "created_by_name": {
            "name": "created_by_name",
            "value": "jack"
        }
    }
}

from this C# POCO, which plays nicely with ServiceStack:

public class lead {
    public string assigned_user_name { get; set; }
    public string modified_by_name { get; set; }
    public string created_by_name { get; set; }
}

I have to do this sort of conversion for lots of different classes, so I don't think it's wise to create another strongly typed class (ala Costomising the serialisation/serialised JSON in service stack)

I've looked through the ServiceStack docs, but maybe I missed an example of this somewhere.

How do I build this JSON in a way that I can extend to other ServiceStack POCOs?

Community
  • 1
  • 1
cam
  • 121
  • 1
  • 8

3 Answers3

3

This produces the right JSON:

        Dictionary<string, Dictionary<string, string>> nameValues = new Dictionary<string, Dictionary<string, string>>();

        // Deal with all the properties on the object
        IList<PropertyInfo> props = new List<PropertyInfo>(this.GetType().GetProperties());
        foreach (PropertyInfo prop in props)
        {
            Dictionary<string, string> nameValue = new Dictionary<string, string>();
            nameValue.Add("name", prop.Name);
            object propValue = prop.GetValue(this, null);
            if (propValue == null)
            {
                nameValue.Add("value", string.Empty);
            }
            else
            {
                nameValue.Add("value", prop.GetValue(this, null).ToString());
            }

            nameValues.Add(prop.Name, nameValue);
        }

        Dictionary<string, object> nameValuesArray = new Dictionary<string, object>();
        nameValuesArray.Add("name_value_list", nameValues);
        string jsonString = JsonSerializer.SerializeToString<Dictionary<string, object>>(nameValuesArray);

The reflection stuff is so that I can use it on any object later.

It's just a matter of constructing the right dictionary for the desired JSON output - in this case a dictionary -> dictionary -> dictionary. Trial and error... :/

Update

Altered it slightly (thanks paaschpa) to use a generic NameValue class because Dictionaries look ugly. I also got the requirements wrong. The JSON should be this:

[
    {
        "name": "id",
        "value": "60e03cb3-df91-02bd-91ae-51cb04f937bf"
    },
    {
        "name": "first_name",
        "value": "FancyPants"
    }
]

which you can do like this:

public class NameValue
{
    public string name { get; set; }
    public string value { get; set; }
}

public class Lead
{
    public string assigned_user_name { get; set; }
    public string modified_by_name { get; set; }
    public string modified_user_name { get; set; }

    public List<NameValue> toNameValues()
    {
        List<NameValue> nameValues = new List<NameValue>();

        IList<PropertyInfo> props = new List<PropertyInfo>(this.GetType().GetProperties());
        foreach (PropertyInfo prop in props)
        {
            NameValue nameValue = new NameValue();

            object propValue = prop.GetValue(this, null);
            if (propValue != null && !String.IsNullOrEmpty(propValue.ToString()))
            {
                nameValue.name = prop.Name;
                nameValue.value = propValue.ToString();
                nameValues.Add(nameValue);
            }
        }

        return nameValues;
    }
}

I'm leaving my original question as is (and my above answer) because it's still a legit example and proper JSON.

cam
  • 121
  • 1
  • 8
1

Well, I don't think .NET dictionaries, lists, arrays, etc. will be helpful since the JSON you listed doesn't appear to have any arrays (square brackets) it in. I'm guessing most .NET JSON serializers will use square brackets when it hits these types. So, I think this leaves creating your own classes or doing some type of 'string magic' to produce to JSON you need.

Not exactly sure how you are using ServiceStack to talk to SugarCRM, but doing something like below should have ServiceStack.Text.JsonSerializer produce the JSON string you listed.

public class NameValue
{
    public string name { get; set; }
    public string value { get; set; }
}

public class Lead
{
    public NameValue assigned_user_name { get; set; }
    public NameValue modified_by_name { get; set; }
    public NameValue created_by_name { get; set; }
}

public class LeadRequest
{
    public Lead name_value_list { get; set; }
}

public void JsonTest()
{
    var req = new LeadRequest
        {
            name_value_list = new Lead
                {
                    assigned_user_name = new NameValue {name = "assigned_user_name", value = "joe"},
                    modified_by_name = new NameValue {name = "modified_by_name", value = "jill"},
                    created_by_name = new NameValue {name = "created_by_name", value = "jack"}
                }
        };

        var jsonReq  = ServiceStack.Text.JsonSerializer.SerializeToString(req);
}
paaschpa
  • 4,816
  • 11
  • 15
  • Thanks for the response! This solution involves changing the Lead object and strongly typing it to the desired JSON - which means the rest of my services have to deal with sugarCRM's format. This might be okay in some situations. – cam Jun 26 '13 at 19:04
1

You could create a custom serializer for the lead class.

JsConfig<lead>.SerializeFn = lead => {
    // Use reflection to loop over the properties of the `lead` object and build a dictionary
    var data = new Dictionary<string, object>();
    foreach (var property in typeof(lead).GetProperties()) {
        data[property.Name] = new {
            name: property.Name,
            value: property.GetValue(lead, null);
        };
    }
    return data.ToJson();
};

You could make this generic by having all classes that you want to serialize in this way implement a marker interface, for example ISugarCrmRequest, and register this custom serializer for all implementations of that interface.

Mike Mertsock
  • 11,825
  • 7
  • 42
  • 75
  • This is a good suggestion. I still need to be able to serialize Lead as a plain ServiceStack Response - I wonder if this would play nicely. – cam Jun 26 '13 at 19:37
  • Ah, I'm not sure if there's any way inside the custom serialization function to get any sort of context about the request that you could use to determine which type of serialization to use. Perhaps a better approach would be to use a request or response filter to control the serialization. – Mike Mertsock Jun 26 '13 at 19:51