New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
An object is serialized as an array and can't be deserialized #2906
Comments
Unfortunately, the official Microsoft documentation doesn't seem to know about a Without knowing details regarding the Ideally, you would base this converter on the generic Then configure the (de)serializer to use this JsonConverter. This can be done in a number of ways, and which you choose depends specifically on how you set up and do the de/serialization. Arguably, the most common way is to configure a (P.S.: I am not the author/maintainer of the library; just a user like yourself.) |
Thanks @elgonzo It is weird that Microsoft.Reporting.WebForms.ReportHierarchy class is not documented any where online but it is part of the Microsoft reporting viewer. Now I am trying to do pretty much what you suggested i.e. create an instance of ReportHeirarchy and populate all members from Json text. But that seems to be not possible either as that class doesn't have a parameter less constructor (public or private) so Activator.CreateInstance throws exception (I have to use reflection because it is not part of the referenced DLL but report viewer creates it runtime and saves it to session). Wonder how Newtonsoft library is creating instances without parameter less constructors. |
I wish there is a way to pass 'JsonObject' attribute through JsonSerializationSettings in addition to placing the attribute on the class. That will solve this problem. |
There is a way to achieve something similar by creating a custom contract resolver (by deriving from But quite likely, this wouldn't get you far. I don't know the
Activator.CreateInstance is not limited to parameterless constructors. There are Activator.CreateInstance overloads that accept values to be passed as arguments to parameterized constructors. Generally speaking, i wonder what you are trying to do here. Considering that |
ReportHeirarchy doesn't have it's own state other than being a stack. As you pointed out, serializing the stack would lose the data as the data is held in it's private fields. I need to somehow apply MemberSerialization.Feilds to it so it saves the data. I am aware that Activator.CreateInstance has overloads that take constructor parameters but I can't or don't want to call those. If the internal state is restored back during deserialization then there is no need for calling the constructor. Similar to a binary formatter serializer which simply saves the 'state' of an instance and restores back. What I am doing here is part of moving our AspNet sessions to an external storage like Redis. I am not trying to serialize the report control, of course we shouldn't save controls or pages to the session. But the report controller internally saves the data to session (probably to maintain current page, current report etc.). Unfortunately we are using a very old report viewer library which was probably designed for binary serialization but not Json. Now, I am trying outside the application using the simple class below to see if it can be done. Let me know how (if possible) the below can be serialized and deserialized back as Dummy object (considering you can't modify the class) . If this works, most likely ReportHeirarchy also will work. Appreciate and
|
No, that's not what i was saying. I am saying that treating an object that is a stack as a JsonObject during serialization will lead to the stack items not being serialized.
Due to a parameterless constructor not existing for your Dummy type, you can't deserialize it from a json array solely relying on Newtonsoft.Json's default serialization behavior. But even with a paremterless constructor, Dummy wouldn't be simply and easily deserializable, due to pecularities of Newtonsoft.Json's implementation failing on trying to deserialize Stack-derived types even when they have a parameterless constructor (a Dummy type derived from List<T> for example would be of no issue for Newtonsoft.Json). In such a case where a type derived from Stack<T> needs to be deserialized, a json converter would be one of the possible workarounds to avoid this issue Newtonsoft.Json's implementation is having with Stack-derived types. (As a side note: If you were to rely on Newtonsoft.Jsons serialization/deserialization for stacks, note that it has a peculiar behavior regarding stacks where the order of the items in the deserialized stack instance are being reversed compared to the original stack instance used for serialization. Iirc - but i might be wrong - System.TextJson also has this peculiar behavior regarding stack serialization/deserialization.)
But you are not using the old binary serialization mechanism here anymore. Don't equate a json serializer to .NET's old and deprecated binary serialization mechanism. Whatever the old binary serialization infrastructure does has no bearing on Newtonsoft.Json's capabilities. Newtonsoft.Json has not the luxury of being an integrated component of the CLR. So, if you don't have an |
Stack items are serialized even when it is serialized as JsonObject. This can be done by adding MemberSerialization.Feilds to the JsonObject attribute of the class. Sadly it is not working when setting it through contract resolver. I have created a ContractResolver extending the DefaultContractResolver and override the CreateContract method and setting the MemberSerialization.Feilds. It just ignores it. It works if I set IgnoreSerializableAttribute to false but that gives another error as the assemblies are not trusted. So in the end, using a custom contract resolver is also not working. protected override JsonContract CreateContract(Type objectType)
{
if (objectType.FullName.Contains("ReportHeirarchy"))
{
JsonObjectContract jsonObjectContract = base.CreateObjectContract(objectType);
jsonObjectContract.MemberSerialization = Newtonsoft.Json.MemberSerialization.Fields;
return jsonObjectContract;
}
return base.CreateContract(objectType);
} |
Ah, okay. So there is some ReportHierarchy field through which the stack items are accessible. I missed that earlier. My apologies... If ReportHierarchy doesn't have a public constructor, setting the contract type to JsonObjectContract alone won't work, as Newtonsoft.Json by default does not invoke private/internal/protected constructors by default. At the least you would have to manually configure the JsonObjectContract to use any such non-public constructor. (As you can't set attributes on the desired ReportHierarchy constructor of choice, you would have to directly manipulate the JsonObjectContract. And how to do that correctly and robustly i don't know, because the whole contract business is very poorly undocumented. Look at the contract's Aside from that, not sure what to suggest anymore. I don't know any implementation details of that ReportHierarchy type, so i am flying blind here :-( |
@elgonzo Do you know how to address this issue? At runtime I can see my AppDomain is fully trusted but still getting the error. |
No, unfortunately not. :-( |
When deserializing an object, getting the error 'Cannot create and populate list type Microsoft.Reporting.WebForms.ReportHierarchy'. ReportHierarchy is part of Microsoft report viewer and this class extends Stack<Reportinfo> so when serializing it, it gets serialized an array instead of as an object. On stack overflow I see suggestions to add JsonObject attribute to the class but this class is in a third party library and I have no access to the class. What is the possible solution to fix this issue? Is there anything that can be set to JsonSerializationSettings instead of an attribute?
Thanks
Murty
The text was updated successfully, but these errors were encountered: