5

I have a WebMethod that looks like this which is used to populate a jqGrid

[System.Web.Script.Services.ScriptService]
public class MyWebService: System.Web.Services.WebService
{
    [WebMethod]
    [Authorize(Roles = "Admin")]
    public object GetPeople(bool _search, double nd, int rows, int page, string sidx, string sord)
    {
        var tbl = new DynamicModel("ConnStr", tableName: "Person", primaryKeyField: "ID");
        var results = tbl.Paged(orderBy: sidx + " " + sord, currentPage: page, pageSize: rows);
        return results;
    }

}

"results" is a System.Dynamic.ExpandoObject with the properties Items, TotalPages, TotalRecords

The json I get back on the from the webservice looks like this

{
"d": [{
    "Key": "TotalRecords",
    "Value": 1
}, {
    "Key": "TotalPages",
    "Value": 1
}, {
    "Key": "Items",
    "Value": [
        [{
            "Key": "Row",
            "Value": 1
        }, {
            "Key": "ID",
            "Value": 1
        }, {
            "Key": "Name",
            "Value": "Test Template"
        }]
    ]
}]
}
} // Don't know why firebug put this extra bracket

Ideally I'd prefer that it comes back without all the Key and Value business as it bloats out the json unnecessarily and doesn't play nicely with jqGrid.

Is there a way to change the way ASP.NET is handling the serialization of the ExpandoObject?

Christian Strempfer
  • 7,291
  • 6
  • 50
  • 75
Sean Tomlins
  • 365
  • 3
  • 13
  • A friend recommended this approach http://stackoverflow.com/questions/5156664/how-to-flatten-an-expandoobject-returned-via-jsonresult-in-asp-net-mvc but I don't know how to register the JavaScriptConverter with the JavaScriptSerializer that the webmethod uses. – Sean Tomlins Feb 21 '12 at 23:23
  • Damn, the answer I seek is here http://msdn.microsoft.com/en-us/library/bb763183.aspx about half way down – Sean Tomlins Feb 21 '12 at 23:52
  • Good to know that you learnt something new :) – Jull Feb 22 '12 at 00:03

1 Answers1

4

It sounds like you've already figured this out, but here's something I threw together a while back to do just that:

public class ExpandoObjectConverter : JavaScriptConverter {
  public override IEnumerable<Type> SupportedTypes {
    get { return new ReadOnlyCollection<Type>(new List<Type>(new Type[] { typeof(ExpandoObject) })); }
  }

  public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) {
    ExpandoObject expando = (ExpandoObject)obj;

    if (expando != null) {
      // Create the representation.
      Dictionary<string, object> result = new Dictionary<string, object>();

      foreach (KeyValuePair<string, object> item in expando) {
        if (item.Value.GetType() == typeof(DateTime))
          result.Add(item.Key, ((DateTime)item.Value).ToShortDateString());
        else
          result.Add(item.Key, item.Value.ToString());
      }

      return result;
    }
    return new Dictionary<string, object>();
  }

  public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer) {
    return null;
  }
}

Then, you just need to add it to the <converters> section in your web.config, as shown in the MSDN article you linked to:

<configuration>
  <system.web.extensions>
    <scripting>
      <webServices>
        <jsonSerialization>
          <converters>
            <add name="ExpandoObjectConverter" type="ExpandoObjectConverter"/>
          </converters>
        </jsonSerialization>
      </webServices>
    </scripting>
  </system.web.extensions>
</configuration>
Dave Ward
  • 59,815
  • 13
  • 117
  • 134
  • Yeah, hopefully this helps someone else. Although the should be shame on MSDN. Thanks for your quick reply Dave, love the work, love the tekpub vids – Sean Tomlins Feb 22 '12 at 01:13
  • @SeanTomlins: Ack, there's what I get for blindly trusting MSDN! Thanks for pointing that out. I edited my answer and pinged someone at MS to hopefully get that error fixed. – Dave Ward Feb 22 '12 at 01:48
  • Works great except when the Value is null. Added a check for it and works fine. `foreach (KeyValuePair item in expando) { if (item.Value == null) result.Add(item.Key, string.Empty); else if (item.Value.GetType() == typeof(DateTime)) result.Add(item.Key, ((DateTime)item.Value).ToShortDateString()); else result.Add(item.Key, item.Value.ToString()); }` – sarme Apr 23 '15 at 21:58