I'm trying to get my C# class to serialize to a json that complies with GP Job, for example:

      "jobId" : "jb10b153b77e74a839e31af53e5d4d0d1", 
      "jobStatus" : "esriJobSucceeded", 
      "results" : {
        "output_Buffer" : {"paramUrl" : "results/output_Buffer"}, 
        "Final_wellpoints" : {"paramUrl" : "results/Final_wellpoints"}
      "inputs" : {
        "Input_Features" : {"paramUrl" : "inputs/Input_Features"}, 
        "Distance" : {"paramUrl" : "inputs/Distance"}
      "messages" : [
        {"type" : "esriJobMessageTypeInformative", "description" : "Submitted."}, 
        {"type" : "esriJobMessageTypeInformative", "description" : "Executing..."}, 
        {"type" : "esriJobMessageTypeInformative", "description" : "Succeeded."}

But my dictionaries (results and inputs) serialize with key/value cruft:

            {"Key":"output_Buffer",     "Value":      {"paramUrl":"results/output_Buffer"}},    
            {"Key":"Final_wellpoints",     "Value":        {"paramUrl":"results/Final_wellpoints"}}], 
            {"Key":"Input_Features",     "Value":        {"paramUrl":"inputs/Input_Features"}},    
            {"Key":"Distance",     "Value":        {"paramUrl":"inputs/Distance"}}], 
            {"type":"esriJobMessageTypeInformative",     "description":"Submitted."},    
            {"type":"esriJobMessageTypeInformative",     "description":"Executing..."},    
            {"type":"esriJobMessageTypeInformative",     "description":"Succeeded."}

Update: I've commented out the WCF code and replaced with Json.NET call.

public class GPJob
    public static string Test()

        Dictionary<string,taskParam> resDict = new Dictionary<string,taskParam>();
        resDict.Add("output_Buffer",new taskParam(){ paramUrl = "results/output_Buffer"});
        resDict.Add("Final_wellpoints",new taskParam(){ paramUrl = "results/Final_wellpoints"});
        Dictionary<string,taskParam> inputDict = new Dictionary<string,taskParam>();
        inputDict.Add("Input_Features", new taskParam(){paramUrl="inputs/Input_Features"});
        inputDict.Add("Distance", new taskParam(){paramUrl="inputs/Distance"});

        GPJob job = new GPJob
            jobId = "jb10b153b77e74a839e31af53e5d4d0d1",
            jobStatus = "esriJobSucceeded",
            results = resDict,
            inputs = inputDict,
            messages = new List<message>()
                new message(){type="esriJobMessageTypeInformative",description = "Submitted."},
                new message(){type="esriJobMessageTypeInformative",description = "Executing..."},
                new message(){type="esriJobMessageTypeInformative",description = "Succeeded."}

        string json = JsonConvert.SerializeObject(job,Formatting.Indented);
        return json;
        DataContractJsonSerializer ser = new DataContractJsonSerializer(job.GetType());
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        ser.WriteObject(ms, job);
        string json = Encoding.Default.GetString(ms.ToArray());
        return json;

    public string jobId { get; set; }
    [DataMember(Order = 1)]
    public string jobStatus { get; set; }

    [DataMember(Order = 2)]
    public Dictionary<string, taskParam> results { get; set; }

    [DataMember(Order = 3)]
    public Dictionary<string, taskParam> inputs { get; set; }
    [DataMember(Order = 4)]
    public List<message> messages { get; set; }

public class taskParam
    public string paramUrl { get; set; }
public class message
    public string type { get; set; }
    [DataMember(Order = 1)]
    public string description { get; set; }

Here's the output:

  "jobId": "jb10b153b77e74a839e31af53e5d4d0d1",
  "jobStatus": "esriJobSucceeded",
  "results": {
    "output_Buffer": {
      "paramUrl": "results/output_Buffer"
    "Final_wellpoints": {
      "paramUrl": "results/Final_wellpoints"
  "inputs": {
    "Input_Features": {
      "paramUrl": "inputs/Input_Features"
    "Distance": {
      "paramUrl": "inputs/Distance"
  "messages": [
      "type": "esriJobMessageTypeInformative",
      "description": "Submitted."
      "type": "esriJobMessageTypeInformative",
      "description": "Executing..."
      "type": "esriJobMessageTypeInformative",
      "description": "Succeeded."

Update2 Looks like I spoke too soon, deserialization of this string fails:

string json = "{\"jobId\":\"jeabfba358b69412abeafd63e415957bf\",\"jobStatus\":\"esriJobWaiting\"," + 
GPJob j= JsonConvert.DeserializeObject(json, typeof(GPJob),JsonSerializerSettings) as GPJob;

I get this exception:

Cannot deserialize JSON array into type 'System.Collections.Generic.Dictionary`2[System.String,Anadarko.iMaps.JobLib.taskParam]'

It works ok when the results and inputs are not empty.


This string deserializes:


So here's the hack:

// hack: replace [] with null
string hackedJson = json.Replace("[]", "null");
GPJob j= JsonConvert.DeserializeObject(hackedJson, typeof(GPJob)) as GPJob;

Of course this results in a null instead of an empty dictionary. Any idea where that might cause an issue (if so, I guess I could handle that in the setters).

  • Huh. In some respects, I'd be tempted to say that Json.NET is right - you can't deserialize an array into a dictionary. Does the bit below work better: string json = "{\"jobId\":\"jeabfba358b69412abeafd63e415957bf\",\"jobStatus\":\"esriJobWaiting\"," + "\"results\":{},\"inputs\":{},\"messages\":[]}"; Here, we're saying that both results and inputs are null objects, not empty arrays. – Herb Oct 5 '10 at 17:48
  • Thanks, herb, I've done a hack with a variant of your suggestion. – Kirk Kuykendall Oct 5 '10 at 18:11
  • So you're going to be getting broken json data? Ick. With respect to the null values, have you played with the JsonSerializerSettings to see if those would help you out? It seems as though you could set NullValueHandling to Ignore, and it would leave the dictionaries alone (assuming you'd created them in the class constructor). – Herb Oct 5 '10 at 18:31
  • Setting to ignore fixes it so my member dictionaries aren't set to null, they remain empty dictionaries, created in the constructor. Thanks again. – Kirk Kuykendall Oct 5 '10 at 18:46

According to this, I'm going to say probably not, at least not without doing some extra work yourself. You can override the values used for Key and Value, but you're going to get the same thing as you have. You need a way to ditch representation of properties as a collection - as the underlying runtime appears to treat the dictionary as IEnumerable.

I think the short answer is to not use DataContractSerializer, and instead use an alternative method, such as Json.NET.

  • I've only been playing with it for ... oh, a day, and yeah, it's pretty nice. Wouldn't have found it were it not for your question. – Herb Oct 5 '10 at 12:37

Apparently that's how the DataContractJsonSerializer is supposed to work, per this bug submittal at Microsoft Connect.

A workaround for this is referred to in the same post.

  • Wow. I had to retrieve the link for that workaround with archive.org, but that solution was exactly what I needed! Thank you so much for that. – Nyerguds Aug 6 '15 at 19:55
  • Just FYI... I expanded (and somewhat optimized) the class, and posted it as answer on a similar question on stackoverflow here: stackoverflow.com/a/31864584/395685 – Nyerguds Aug 12 '15 at 8:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.