6

When building a response in WCF (json), im pretty sure it's not possible to use completely dynamic objects, but just wanted to double check here first.

An ideal response would look something like:

"userTypes"  :
                    {
                        "BartSimpson" :
                            {
                                "url" : "foo",
                                "desc" : "bar"
                            },
                        "LisaSimpson" :
                            {
                                "url" : "foo",
                                "desc" : "bar"
                            }
                    }

In 'compiled' code, the above could be performed by the following architecture (slightly pseudocode):

public class Character{
string url {get;set;}
string desc{get;set;}
}

public class UserTypes{
 public Character BartSimpson{get;set;}
 public Character LisaSimpson{get;set;}
}

But my main goal is that BartSimpson and LisaSimpson are not 'compiled' so I could have any number of Character classes, with any name / identifer in the response.

maxp
  • 24,209
  • 39
  • 123
  • 201

1 Answers1

5

Add the following using at the top of your service implementation class (make sure that you also add the proper references in your project):

using Newtonsoft.Json;
using System.Dynamic;
using System.IO;
using System.Text;

You may try this simple method which outputs the dynamic result:

public string GetData()
{
    dynamic d = new ExpandoObject();
    dynamic bartSimpson = new ExpandoObject();
    dynamic lisaSimpson = new ExpandoObject();
    bartSimpson.url = "foo";
    bartSimpson.desc = "bar";
    lisaSimpson.url = "foo";
    lisaSimpson.desc = "bar";
    d.userTypes = new ExpandoObject();
    d.userTypes.BartSimpson = bartSimpson;
    d.userTypes.LisaSimpson = lisaSimpson;
    var s = JsonSerializer.Create();
    var sb = new StringBuilder();
    using (var sw = new StringWriter(sb))
    {
        s.Serialize(sw, d);
    }
    return sb.ToString();
}

To go one more step further (you'll just have to pass Bart and Lisa in the comaSeparatedNames value), you could do:

public string GetData(string comaSeparatedNames)
{
    string[] names = comaSeparatedNames.Split(',');
    dynamic d = new ExpandoObject();
    dynamic dNames = new ExpandoObject();
    foreach (var name in names)
    {
        dynamic properties = new ExpandoObject();
        properties.url = "foo";
        properties.desc = "bar";
        ((IDictionary<string, object>)dNames).Add(name, properties);
    }
    ((IDictionary<string, object>)d).Add("userTypes", dNames);

    var s = JsonSerializer.Create();
    var sb = new StringBuilder();
    using (var sw = new StringWriter(sb))
    {
        s.Serialize(sw, d);
    }

    // deserializing sample
    //dynamic dummy = new ExpandoObject();
    //var instance = s.Deserialize(new StringReader(sb.ToString()), 
    //    dummy.GetType());
    //var foo = instance.userTypes.BartSimpson.url;

    return sb.ToString();
}

Note: I've also provided the lines (commented) for deserialization.

Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
  • 1
    Edit: I assume you're using `Newtonsoft.Json` for serialization. – maxp Jul 23 '13 at 10:39
  • 1
    Thanks for such a comprehensive code example. I'm currently working through it. Unfortunately now that my return type is defined as a `string`, my response seems to have all values escaped? – maxp Jul 23 '13 at 11:09
  • 2
    It's okay, i found the solution here: http://stackoverflow.com/questions/3078397/returning-raw-json-string-in-wcf – maxp Jul 23 '13 at 11:20
  • 1
    Okay, this is a brilliant solution thanks very much. Some cool things Ive noticed: Dynamic Properties can also be added in the following fashion: (d as IDictionary).Add("bart simpson", bart);` Yes - this allows properties with 'spaces' in between. Also `bart` can be a strongly typed class, so you can mix & match `ExpandoObject` with strongly typed objects. – maxp Jul 23 '13 at 11:57