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

inserting a dynamic variable into a JSON string

My goal is to create a javascript object, var systemName = {"system" : varA}; However, I want the object to be structured like `{"system" :"varA"} where varA contains the variable value but is enclosed in double quotes. I attempted {"system" : "'+ ...

Mastering the art of invoking a JavaScript function from a GridView Selected Index Changed event

In my current setup where I have a User Control within an Aspx Page and using Master Page, there's a GridView in the User Control. My goal is to trigger a javascript function when the "Select" linkbutton on the Gridview is clicked. Initially, I succe ...

What is the maximum number of files that FileUploader can accept when multi-select is enabled?

I encountered the following issue: A first chance exception of type 'System.Web.HttpException' occurred in System.Web.dll Additional information: Maximum request length exceeded. while attempting to upload 250 JPEG files, each around 98 KB in ...

What is the proper jQuery traversal method to display a single templated element?

Utilizing handlebars as the view engine for node.js, the subsequent html content is dynamically produced and repeated: http://jsfiddle.net/4Q5PE/ <div class="btnsContainer"> <div class="btn-group" data-toggle="buttons"> <label cla ...

Learn how to update image and text styles using Ajax in Ruby on Rails with the like button feature

I'm working on implementing a Like button in Rails using Ajax, similar to this example: Like button Ajax in Ruby on Rails The example above works perfectly, but I'm interested in incorporating images and iconic text (such as fontawesome) instead ...

Accessing the Div id stored in a session parameter

Is there a way to store the id (div id) into a session variable? This is an example of my code below: <div class='fieldRow'>Options </div> <div id="abcde"></div> <div class='Row'> <?php $user_typ ...

Sharing socket data between different namespaces in Socket.ioSocket.io enables the

Is there a solution to sharing data set in a socket in one namespace and accessing it on another namespace? While I understand that data can be attached to the socket object itself, a problem arises when trying to access the data in a different namespace. ...

Generate a dynamic drop-down menu by populating it with the names from a JSON array

I'm having trouble populating a drop-down menu with object category names using HTML and jQuery. Can anyone provide some assistance? For example: JSON window.cars = { "compact": [ { "title": "honda", "type": "accord", "thumbnail": " ...

Instead of using a computed getter/setter, make use of mapState and mapMutations to simplify

Currently, I am syncing a computed value to a component and using a computed setter when it syncs back from the component. I'm wondering if there is a more concise way to replace a computed getter/setter with mapState and mapMutations. How can this b ...

Show information from a JSON response using Ajax and present it on a jQuery dialog within an MVC3 view

I currently have an ActionResult method within a Controller which retrieves a row of data (such as id, name, city, etc) from the database based on the provided ID [HttpPost] public ActionResult Get(Guid Id) { Ref imp = ReadRepository.G ...

Modifying TextField color in a react application with Material UI

I have a react component that consists of a text field and a button. I want these elements to be displayed in green color on a black background, but I am unable to modify the default colors of all the elements. Following a similar query on how to change th ...

Invoke a function via ajax with no return value

Here is the ajax code I am using to call an action in Controller B while currently in Controller A. The params are sent to the action correctly, but the view does not render as expected. I suspect that it may be returning the view instead. Index.cshtml (o ...

WCF API encountering issue with Ajax request

I encountered the following error: The exception message is 'The incoming message has an unexpected message format 'Raw'. The expected message formats for the operation are 'Xml', 'Json'. This can be because a WebC ...

I am encountering an issue where the useState hook is returning an undefined value on separate components, even after

When setting up a login context, I wrap all my routes with the context provider and pass the initial value using useState: <userContext.Provider value={{loggedUser, setLoggedUser}}> In LogInMenu.jsx, which is responsible for setting the loggedUser ( ...

Ways to ensure that a FILE type object is able to be serialized as

When attempting to send a JSON response in Django, I encountered the following error: TypeError: Object of type File is not JSON serializable This error was caused by utilizing type <class 'django.core.files.base.File'> in my JSON respon ...

Tips for handling a disabled button feature in Python Selenium automation

When trying to click this button: <button id="btn-login-5" type="button" class="m-1 btn btn-warning" disabled="">Update</button> I need to remove the disable attribute to make the button clickable. This ...

Integrating a bokeh chart within a Flask application

Upon accessing localhost:5002/simpleline via Flask, I was hoping for a straightforward bokeh plot. Instead, what I encountered was unexpected: ('', ' ') I have two essential files involved in this process. Firstly, the Python file: f ...

The reactivity of VUE 3 arrays is not being updated, but individual array elements accessed using array

Currently facing an issue while trying to connect a dynamically updating array of objects to a Konva circle. The circles are appearing as expected, but the problem arises within a for loop where I update player locations based on a "tick". While setting th ...

Highlight particular terms (key phrases) within text contained in a <td> tag

I am currently working on a project and facing a challenge that I am unfamiliar with. My task is to highlight specific keywords within text located inside a <td> element. I cannot manually highlight the keywords as the texts are dynamic, originating ...

Can the state and city be filled in automatically when the zip code is entered?

I have a form where users can enter their zip code, and based on that input, the corresponding city and state will automatically populate. These three fields are positioned next to each other within the same form. Here is an example of my form: $(' ...