How to return Dictionary with WebAPI

2019-06-23 22:50发布

I'm providing a WebApi 2 endpoint that is done in this way:

My controller is simply:

 public IDictionary<MyClass, int> GetMyClasses(string id)
 {
    Dictionary<MyClasses, int> sample = new Dictionary<MyClasses, int>();

    sample.Add(new MyClasses()
    {
       Property1 = "aaa",
       Property2 = 5,
       Property3 = 8
    },10);

    return sample;
 }

The structure of MyClass is:

public class MyClass
{
   string Property1 {get;set;}
   int Property2 {get;set;}
   int Property3 {get;set;}
}

When I run my webservice, the helper webpage shows me that the expected outputs are:

{ "MyNamespace.MyProject.MyClass": 1 }

On the other hand the xml sample is what I'd like (except that I want the json, not the xml):

<ArrayOfKeyValueOfMyClassintl85fHlC_P xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
  <KeyValueOfMyClassintl85fHlC_P>
    <Key xmlns:d3p1="http://schemas.datacontract.org/2004/07/MyNamespace.MyProject.MyClass">
      <d3p1:Property1>sample string 4</d3p1:Property1>
      <d3p1:Property2>8</d3p1:Property2>
      <d3p1:Property3>5</d3p1:Property3>
    </Key>
    <Value>1</Value>
  </KeyValueOfMyClassintl85fHlC_P>
</ArrayOfKeyValueOfMyClassintl85fHlC_P >

I also ran the endpoint with Postman and it confirms that the returned value is the one previewed by the WebApi out of the box page.

Why the json is "wrong" and the xml is well done (I mean that contains all the data)?

UPDATED:

I expected MyClass serialized in json like this:

{
  "Property1": "sample string 4",
  "Property2": 8,
  "Property3": 5
}

This should be the structure of the key of my dictionary, as it is in the xml representation.

Thanks

3条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-06-23 23:05

This is kind of hacky, but I had success by converting the Dictionary to a List object before running it through JsonConvert. Check it out:

IDictionary<MyClass,int> dict = new Dictionary<MyClass, int>();
MyClass classy = new MyClass() { value = value };
dict.Add(classy, 5);
string json = JsonConvert.SerializeObject(dict); //<--- Returns [{MyClass: 5}], boo

Whereas . . .

string json = JsonConvert.SerializeObject(dict.ToList()); //<--- Returns [{Key: blah blah blah, Value: 5}], nice

Hope that helps.

查看更多
Viruses.
3楼-- · 2019-06-23 23:09

What does your Controller look like? The endpoint should look something like this:

[Route("")] 
public IHttpActionResult Get() 
{ 
    IDictionary<MyClass, int> resource = new Dictionary<MyClass, int> 
    {
        { new MyClass {Property1="1", Property2=2, Property3=3}, 0 },
        { new MyClass {Property1="11", Property2=22, Property3=33}, 1 },
    };

    return Ok(resource); 
} 

If you're still having JSON serialization issues after that, you can configure the default JsonFormatter type in Web API: GlobalConfiguration.Configuration.Formatters.JsonFormatter;. See the ASP.NET Web API Serialization Documentation for more information.

查看更多
冷血范
4楼-- · 2019-06-23 23:21

Typically dictionaries are used to produce more dynamic JSON objects, by using the Key/Value pairs as name/value pairs on a JavaScript object. But a JSON object cannot use another JSON object as its key. For example, the following syntax is not valid:

{
    {"Property1": "sample string 4",... } : 1,
    {"Property1": "sample string 5",... } : 2,
}

So you'll need to decide exactly how you want this information represented in JSON. Are you thinking of it as an array of Key/Value objects?

[ 
    { Key: {"Property1": "sample string 4",...}, Value: 1 },
    { Key: {"Property1": "sample string 5",...}, Value: 2 },
]

In that case, return a List<KeyValuePair<string, int>> from your method, via dict.ToList().

Do your keys and values have meanings? Perhaps you should create a class to represent each item with custom property names, via dict.Select(kvp => new MyDto { MyClass = kvp.Key, Foo = kvp.Value }).ToList():

[ 
    { MyClass: {"Property1": "sample string 4",...}, Foo: 1 },
    { MyClass: {"Property1": "sample string 5",...}, Foo: 2 },
]

Do you want to stick with objects, but have the left-hand side be a string representation of your class? You can do this by implementing the ToString() method on MyClass:

{ 
    "sample string 4|8|5": 1, 
    "sample string 5|6|7": 2
} 
查看更多
登录 后发表回答