Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.NET Web API issues with deserializing JSON to object

I overtook a project which was developed by a company for us, unfortunately we do not get much support and in the long term, we should accomplish maintainence by ourselves for it. The application consists of a simple Web client (HTTP, JavaScript, Knockout Framework) and a REST API Service (.NET 4.5, ASP.NET MVC I guess).

Currently I am only modifiying the client, so the Server should still work as expected.

On the clientside I modified the Knockout View Model a little bit (added some computables and optimized presentation of some values). The View Model consists of 'Issues' and 'Comments' (as an array on issues, its an Bug tracker in fact). If I create a new issue, description is added to a first comment, the whole Model is JSON.stringified and the send to the .NET API Service. I prooved with Firebug, that the JSON that gets posted looks like this:

{
   "Id":0,
   "Title":"THis is a title",
   "Comments":[
       {
          "Id":1,
          "Text":"this is the first comment"
       }
   ]
}

On the client side, I have a "IssueController":

[HttpPost]
public HttpResponseMessage PostIssues( Issue issue ) {
   //issue should already hold the deserialized content of the JSON here,
   //but it only contains 'Id' and 'Title' not the 'Comments' (empty List)
   ...
}

The issue domain model object also has an array for holding comments, but on this end its empty already. The .NET code doesn't have any part which explicitely parses the JSON, as far as I understood it, the MVC Framework does this implicitely by equal property names (Is that right?).

The deserialization already worked as expected, so the .NET Code should be fine, but I looks like that I have modified the JSON in a way, that this implicit mapping of comments does not work anymore. Unfortunately I dont have much experiences with the .NET MVC Framework (or is it just the .NET WebAPI Framework, cannot even tell you that).

These are my questions:

  1. What kind of .NET REST API Framework is that? How can I distinguish?
  2. How is this implicit JSON deserialization working, and what are its pitfalls, for example when portions of the JSON doesn't get deserialized as expected? Especially on the client side (as I said, I didn't modify the server code)
  3. Any ideas about what I could have done to the JSON, that the server doesn't like it anymore? ;)

EDIT

Issue.cs looks like this (simplified for sure):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Bo;
using Projects.DomainObjects;

namespace Projects.Models {


public class Issue : DomainObject {

    public Issue() {

        this.Comments = new List<Comment>();
    }

    public long Id { get; set; }

    private string _Title;
    public string Title { get { return _Title; } set { _Title = value; NotifyChanged(); } }

    public List<Comment> Comments { get; set; }
}

Comment.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Common;
using Projects.DomainObjects;

namespace Projects.Models {


public class Comment : DomainObject {

    public Comment() {

    }

    public long Id { get; set; }
    public string Text { get; set; }
}
like image 270
Jürgen Zornig Avatar asked Jan 11 '14 09:01

Jürgen Zornig


People also ask

How do I deserialize JSON in .NET core?

NET objects (deserialize) A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.

What is Deserializing JSON?

JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation (convert string -> object).

Does Newtonsoft JSON support .NET core?

ASP.NET Core 3.0 and above Newtonsoft JSON is available as NuGet Package.


Video Answer


2 Answers

I just tried to your code straight from your post and it worked for me.

So there are a few things that may be going wrong on your side:

  • When you post the object to the server, make sure you are converting back from Knockout observable to a json object. So in your ajax request, make sure it looks like: data: ko.toJSON(issue) and not just data: issue.
  • When you post the object to the server make sure you sent header content-type: application/json

Here are the answers to your other questions:

What kind of .NET REST API Framework is that? How can I distinguish?

This doesn't look like anything custom (at least, what you posted) it is just straight Web API in .NET.

How is this implicit JSON deserialization working, and what are its pitfalls, for example when portions of the JSON doesn't get deserialized as expected? Especially on the client side (as I said, I didn't modify the server code)

Deserialization on the server uses the collection of formatters that work based on the content-type set by the client. This can get complex if you want to customize it but there is information here

Any ideas about what I could have done to the JSON, that the server doesn't like it anymore? ;)

As I said your code worked for me!

like image 190
Greg Ennis Avatar answered Oct 14 '22 22:10

Greg Ennis


Solved it, the Problem was a computed that returns a sorted array of the comments. So my knockout model contains an

self.Comments = ko.observableArray([]); //...which gets filled with the comments of an issue

and a

self.CommentsSorted = ko.computed(function() {...}); //...which simply returns a sorted Comments array

So when I serialize this model, the posted JSON now represents the Comments Array, but also the CommentsSorted Array. Only when I do

var i = ko.toJS(issue);
delete i.CommentsSorted;

before I post i as data, .NET is able to deserialize Comments correctly.

The mysterious thing about this is, that there were always other computed fields in my knockout model, which get ignored completely by .NET and do not disturb deserialization in any way. So it seems that it depends mainly on the name and type of the fields in the model (perhaps if the first letters are equal?).

The good thing: it works now The bad thing: it isn't really deterministic how .NET does the deserialization of JSON data and I am also not able to debug if it doesn't behave as expected.

like image 42
Jürgen Zornig Avatar answered Oct 15 '22 00:10

Jürgen Zornig