-1

I'm working in .Net Core 2.2 with the MVC pattern. I have a Web-API controller, where I created some Endpoints with classic CRUD-methods.

Now I have everything compiling and when I debug my soluting I get an array containing a couple of JSON-formatted objects - but the system sees the output it as an array, not as JSON.

Now I want this array to become a JSON.

I've looked at this: https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JObject.htm

My orginal method looked like this (in controller):

[HttpGet("/ListAllItems")]
public async Task<IEnumerable<DtoModel>> ListAllItemsFromDb()
{
    return  await _dbProvider.ListAllItemsAsync();
}

and gave an output of:

[{"id": "GUID-STRING", "itemName": "foo"}, {"id": "GUID-STRING2", "itemName": "bar"}]

//My frontend did not recognize this as a JSON, since it is an array, and threw an exception

So I tried this in my controller instead

  [HttpGet("/ListAllItems")]
        public async Task<JObject> ListAllItemsFromDb()
        {
            var result = await _dbProvider.ListAllItemsAsync();
            string output = result.ToString(); 
            string json = JsonConvert.SerializeObject(output);
            JObject obj = JObject.Parse(json);
            return obj; 
        }

When I run this code, my error message states: "JsonReaderException: Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path '', line 1, position 60."

How do I make the array of objects into a JSON object?

Emilia
  • 163
  • 4
  • 16
  • 2
    But as it looks your data is not a JSON object, is an array of JSON objects – Gabriel Costin Jul 16 '19 at 08:42
  • 1
    //My frontend did not recognize this as a JSON Then the problem is in your browser/frontend. This is the correct synthax for array of json objects. How do you parse it in your frontend? – Georgi Georgiev Jul 16 '19 at 08:44
  • This has so many bad decisions, I can't even started, why do you use JObject as result of your action, why do you serialize then serialize? Why don't you declare an object like this var result = new { items = await _dbProvider.ListAllItemsAsync()}; – SilentTremor Jul 16 '19 at 08:51
  • `but the system sees the output it as an array, not as JSON.` If you pass out two objects like you are then you will get JSON (just as you show in your question). It is 100% legitimate JSON. That JSON, when deserialised, will result in an array of objects (which makes sense - you have two objects). **If you don't want that, we need to see your JS code to see how you are _processing_ this JSON.** – mjwills Jul 16 '19 at 08:54
  • @Emilia This is almost certainly a XY Problem (https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). Something isn't working, and you've jumped to a conclusion about the nature of the problem. We really need to see the JS code to see if your guess of the problem is accurate or not. – mjwills Jul 16 '19 at 08:59

2 Answers2

2

Your front end might reject JSON arrays because there are some security issues with them. The article Anatomy of a Subtle JSON Vulnerability explains it. But I think it is no longer applicable, see this and this Stack Overflow question

You can however create a wrapper object to avoid returning top level JSON arrays:

public class Wrapper<T> {
   public T Data {get; set;}
}

Then in your controller:

[HttpGet("/ListAllItems")]
public async Task<Wrapper<IEnumerable<DtoModel>>> ListAllItemsFromDb()
{
    return new Wrapper<<IEnumerable<DtoModel>>() {
       Data = await _dbProvider.ListAllItemsAsync()
    };
}

The MVC infraestructure will return a JSON result like this:

{
   Value: [{"id": "GUID-STRING", "itemName": "foo"}, {"id": "GUID-STRING2", "itemName": "bar"}]
}

This should make your front end happy.

Jesús López
  • 6,739
  • 2
  • 26
  • 55
  • That hasn't been an issue for over 10 years. `It didn’t work with IE 6, 7, 8, FireFox 3 nor Google Chrome.` – mjwills Jul 16 '19 at 09:25
  • @mjwills Yes, but there still are frameworks that reject top level JSON arrays. And there are platforms such as SharePoint that never return top level JSON arrays. Anyway, using the wrapper solved the OP issue, so I guess her issue is related to that vulnerability or other related ones such as `There is a second array-related vulnerability: http://haacked.com/archive/2009/06/25/json-hijacking.aspx/ This one uses Object.prototype.__defineSetter__`. – Jesús López Jul 16 '19 at 09:35
  • `Yes, but there still are frameworks that reject top level JSON arrays` Do they exist? Sure, I have no doubt that they do. Is vue.js one of them? No, no it isn't. – mjwills Jul 16 '19 at 23:25
  • Oh, I didn't realize the OP is using Vue.js, sorry. Then, despite the wrapper solved the problem, we still don't know why the front end was rejecting the original JSON. – Jesús López Jul 17 '19 at 05:44
-2

JsonConvert will convert your list with no problems - calling ToString() on IEnumerable<DtoObject> might be your problem.

Pass the list in to JsonConvert and it will parse correctly.

var result = await _dbProvider.ListAllItemsAsync();
string json = JsonConvert.SerializeObject(result);
Aaron
  • 86
  • 1
  • 5