c# JavaScriptConverter - understanding the deserialization of custom properties

I'm facing an issue where I have a JSON serialized class that I am trying to deserialize into an object.

For example:

public class ContentItemViewModel
{
    public string CssClass { get; set; }
    public MyCustomClass PropertyB { get; set; }
}

The simple property (CssClass) can be deserialized using:

 var contentItemViewModels = ser.Deserialize<ContentItemViewModel>(contentItems);

However, there is an error when deserializing PropertyB...

We tried adding a JavaScriptConverter:

  ser.RegisterConverters(new List<JavaScriptConverter>{ publishedStatusResolver});

But when we specified 'MyCustomClass' as a 'SupportedType', the Deserialize method was not called. However, when we specified ContentItemViewModel as the SupportedType, then Deserialize was called.

Currently, our solution involves creating a custom converter like this:

class ContentItemViewModelConverter : JavaScriptConverter
{

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        var cssClass =  GetString(dictionary, "cssClass");           
        var propertyB= GetString(dictionary, "propertyB");

        return new ContentItemViewModel{    CssClass = cssClass , 
                                            PropertyB = new MyCustomClass(propertyB)}
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new Exception("Only does the Deserialize");
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get
        {
            return new List<Type>
                {
                    typeof(ContentItemViewModel)
                };
        }
    }
}

However, we are looking for a simpler solution to only deserialize MyCustomClass without having to modify the converter each time a property is added or changed on the ViewModel.

Is there a way to just Deserialize PropertyB of type MyCustomClass?

Thank you for your assistance!

Answer №1

Are you familiar with the features of DatacontractJsonSerializer

[DataContract]
public class MyCustomClass
{
    [DataMember]
    public string foobar { get; set; }
}

[DataContract]
public class ContentItemViewModel
{
    [DataMember]
    public string CssClass { get; set; }
    [DataMember]
    public MyCustomClass PropertyB { get; set; }
}

class Program
{
    static void Main(string[] args)
    {

        ContentItemViewModel model = new ContentItemViewModel();
        model.CssClass = "StackOver";
        model.PropertyB = new MyCustomClass();
        model.PropertyB.foobar = "Flow";

        //Prepare a stream for object serialization.
        MemoryStream ms = new MemoryStream();

        // Serialize the User object to the stream.
        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContentItemViewModel));
        ser.WriteObject(ms, model);
        byte[] json = ms.ToArray();
        ms.Close();
        string s=  Encoding.UTF8.GetString(json, 0, json.Length);


        Console.ReadLine();
    }
}

If MyCustomClass has derivations, ensure to include all possible classes in DatacontractJsonSerializer.KnownTypes.

Answer №2

Despite the passage of time, I encountered a similar issue and found that the Deserializer lacks awareness of the classes being deserialized unless provided with necessary information.

At the top level, it recognizes the type from the type parameter of Deserialize<>. This explains why your converter for ContentItemViewModel functions correctly. However, for nested objects, the Deserializer requires __type properties and a JavaScriptTypeResolver.

var ser = new JavaScriptSerializer(new SimpleTypeResolver());
ser.RegisterConverters(myconverters);
MyClass myObject = new MyClass();
string json = ser.Serialize(myObject);
    // set a breakpoint here to see what has happened
ser.Deserialize<MyClass>(json);

A TypeResolver adds a __type property to each serialized object. It is possible to create a custom type resolver that uses shorter names. In this example, the SimpleTypeResolver from .net stores the fully qualified type name as __type. During deserialization, the JavaScriptDeserializer locates __type and consults the TypeResolver for the correct type. With this information, it can then call a registered JavaScriptConverter.Deserialize method.

In the absence of a TypeResolver, objects are deserialized to a Dictionary due to the lack of type information in JavaScriptSerializer.

If the json string cannot provide a __type property, one option is to first deserialize to a Dictionary and then implement a step to interpret the fields and determine the correct type. Subsequently, you can utilize the ConvertToType method of JavaScriptSerializer to transfer the dictionary into the object's attributes and properties.

If you are restricted to using the default JavaScriptSerializer provided by ASP.NET and cannot create your own, reference the following section from the .ctor help of JavaScriptSerializer:

The instance of JavaScriptSerializer used by the asynchronous communication layer for invoking Web services from client script employs a specialized type resolver. This resolver limits deserialization to types defined in the Web service method signature or those marked with the GenerateScriptTypeAttribute. Programmatic alterations to this built-in type resolver are not possible.

The GenerateScriptType Attribute may offer assistance, although the specific requirements for __type Properties remain unclear.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Upload an image to a Node.js API using the Next.js API directory

I am working with a file instance that I obtained from the formidable library. Here's how it looks: photo: File { _events: [Object: null prototype] {}, _eventsCount: 0, _maxListeners: undefined, size: 16648, path: 'public/ ...

Validate whether the path parameter in NextJS is null or empty before executing the query

Currently seeking a method to determine if the query value is empty using the path parameter approach. Have a file named pages/search/[variable1].js Below is the code snippet: import { useRouter } from "next/router" const Variable= () => { ...

Building a dynamic SQL Server script for inserting JSON data

It seems like I am facing an issue with my attempt to create a single procedure for inserting data into multiple tables. Here's a snippet of the problem: DECLARE @jsondata varchar(MAX) Set @jsondata='[{"RecordId":1,"CreatedUser&quo ...

What is the method to change lowercase and underscores to capitalize the letters and add spaces in ES6/React?

What is the best way to transform strings with underscores into spaces and convert them to proper case? CODE const string = sample_orders console.log(string.replace(/_/g, ' ')) Desired Result Sample Orders ...

Adjust the dimensions of the initial cell

I need to adjust the size of the initial "generated" cell in a grid. The grid is not present in the HTML markup until JavaScript prints RSS information on it, making it difficult to target specific rows or cells directly. Note: The first element is hidden ...

Issues with grunt - Alert: Task "ngAnnotate:dist" has encountered an error. Proceed using --force option

Encountering an unexpected issue with a Grunt task that previously ran smoothly. The error message is as follows: Running "ngAnnotate:dist" (ngAnnotate) task Generating ".tmp/concat/scripts/scripts.js" from: ".tmp/concat/scripts/scripts.js"...ERROR >& ...

Reset input fields upon jQuery removal

Currently, I am working on a form that includes a remove function. The function is functioning correctly, but I am facing an issue where I want the field values to be cleared when the remove function is triggered. This is necessary as I am sending input va ...

beforeSend method in jquery ajax synchronously calling

One of my functions is called: function callAjax(url, data) { $.ajax( { url: url, // same domain data: data, cache: false, async: false, // use sync results beforeSend: function() { // show loading indicator }, ...

Transfer the information on the onClick event to the loop's function

When creating my component within the parent component, I follow this approach: renderRow(row){ var Buttons = new Array(this.props.w) for (var i = 0; i < this.props.w; i++) { var thisButton=<FieldButton handler={this.actionFunction} key={&ap ...

Navigating through JSON array in Python

I'm currently working with JSON data stored in an array that I am importing into my script. "ip_address": [ "192.168.0.1", "192.168.0.2", "192.168.0.3" ] Upon loading the JSON, I define a variable called ip_address. data = yaml.load(message) fo ...

Exploring Postgres Commands for Manipulating JSON Arrays

One of my tables is called cust_data and it stores ids along with JSON objects. I need to create postgres select queries to retrieve: Get all ids where the persons array does not contain "gender": "Female" [this should return id#3 from the data below] Re ...

TeamCity Server experiences issues with WebDriver's ImplicitlyWait功能

In the process of developing functional tests with Selenium 2 framework on a Firefox 10 environment, we have encountered an issue with a special functionality: driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5)); We are attempting to set u ...

Trouble encountered with JSON integration in a PHP SQL statement

I need the server.php file to return a table of integers, each linked to a key (some integers may share a key). The table should only contain integers linked to a specific key. In order to obtain one of these keys, another key is required as a parameter. ...

Transfer information between two devices remotely through AJAX

I am in the process of developing a web application that utilizes a mobile phone as a controller, similar to this example: . The concept is quite simple - I just need to transfer text entered on the phone to the computer. There is no need for a database, ...

Preventing the window from resizing while an AJAX query is in progress

I have a script in jQuery that serves as a search tool and also has the capability to resize an element to match the screen height minus 40 pixels whenever the window is resized. However, I am looking for a way to turn off the resizing feature when a searc ...

A guide on transforming HTML into a variable using JavaScript

Having trouble converting HTML to a JavaScript variable. This is my HTML code: <div onclick="openfullanswer('2','Discription part','This is the code part');"> I want to create this HTML code dynamically, but I&apo ...

Tips for including custom attributes in Laravel paginated JSON output

Within my index method, I have the following code snippet: public function index() { // dd(Poll::paginate(2)); return response()->json(Poll::paginate(2),200); } The resulting JSON object generated by this method looks like this: ...

Tips for efficiently serving a static file without triggering a disk read

res.sendFile is the preferred method for serving a static file in express. However, it appears that res.sendFile reads the file from disk with each request, as shown below: router.get('/', (req, res) => { res.sendFile('./guest.js&apo ...

Transforming an empty JSON array into an empty JSON object

Here is the Json Object that I am dealing with: "feedback_details":{ "id":"80", "lead_id":"86075", "account_id":"1543", "document_id":"582348", "reason_id":"4", "description":"COAPPL_profile1.jpg", "sales_remark":null, "lat":"", "long":"", "status":"2", ...

Standing alone, an argument can never be fully validated without

Recently, while delving into the valuable resource titled Effective TypeScript by Dan Vanderkam, I stumbled across an intriguing scenario that left me puzzled. Within a code snippet presented in the book, there was a line - shape; that seemed perplexing ...