Removing deserialized mixed list of objects from JSON

I use DataContractJsonSerializerto deserialize objects from an external service. In most cases, it worked fine for me. However, there is one case where I need to deserialize JSON, which contains a list of objects that all inherit from the same base class, but there are many different types of objects in this list.

I know this can be done easily by including a list of known types in the serializer constructor, but I do not have access to the code that generated this JSON service. The types that I use will be different from the types used in the service (basically just the class name and namespace will be different). In other words, the classes that the data was associated with will not be the same classes that I will use for deserialization, even if they are very similar.

With XML, DataContractSerializerI can pass DataContractResolverfor mapping service types to my own types, but there is no such constructor DataContractJsonSerializer. Is there any way to do this? The only options I could find are: write my own deserializer or use Microsoft JsonObject , which is not tested, and "should not be used in production environments."

Here is an example:

[DataContract]
public class Person
{
    [DataMember]
    public string Name { get; set; }
}

[DataContract]
public class Student : Person
{
    [DataMember]
    public int StudentId { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var jsonStr = "[{\"__type\":\"Student:#UnknownProject\",\"Name\":\"John Smith\",\"StudentId\":1},{\"Name\":\"James Adams\"}]";

        using (var stream = new MemoryStream())
        {
            var writer = new StreamWriter(stream);
            writer.Write(jsonStr);
            writer.Flush();

            stream.Position = 0;
            var s = new DataContractJsonSerializer(typeof(List<Person>), new Type[] { typeof(Student), typeof(Person) });
            // Crashes on this line with the error below
            var personList = (List<Person>)s.ReadObject(stream);
        }
    }
}

Here is the error mentioned in the comment above:

Element ':item' contains data from a type that maps to the name
'http://schemas.datacontract.org/2004/07/UnknownProject:Student'. The
deserializer has no knowledge of any type that maps to this name. Consider using
a DataContractResolver or add the type corresponding to 'Student' to the list of
known types - for example, by using the KnownTypeAttribute attribute or by adding
it to the list of known types passed to DataContractSerializer.
+3
source share
3 answers

I have found the answer. It was very simple. I just needed to update the attribute DataContractto indicate which namespace (you can also specify a different name) that they reference in the original JSON, for example:

[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/UnknownProject")]
public class Person
{
    [DataMember]
    public string Name { get; set; }
}

[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/UnknownProject"]
public class Student : Person
{
    [DataMember]
    public int StudentId { get; set; }
}
+1

JsonObject .NET 3.5. Codeplex - http://wcf.codeplex.com - JsonValue/JsonObject/JsonArray/JsonPrimitive, . "" JSON. JSON - JSON.NET http://json.codeplex.com.

0

DTO .

: ()

class JsonDto

string Content {get;set;}
string Type {get;set;}

ctor(object) => sets Content & Type Properties

static JsonDto FromJson(string) // => Reads a Serialized JsonDto 
                                //    and sets Content+Type Properties

string ToJson() // => serializes itself into a json string

object Deserialize() // => deserializes the wrapped object to its saved Type
                     //    using Content+Type properties

T Deserialize<T>()   // deserializes the object as above and tries to cast to T

JsonDto, JSON , , , Deserialize<T>.

One warning: if you set a property Type, you must use AssemblyQualifiedName of this type, but without the version (ex:) attribute MyCompany.SomeNamespace.MyType, MyCompany.SomeAssembly. If you just use the AssemblyQualifiedNameclass property Type, you will get errors if your version of the assembly changes.

I implemented JsonDtoCollectionin the same way that comes from List<JsonDto>and provides methods for handling collections of objects.

class JsonDtoCollection : List<JsonDto>

ctor(List<T>) => wraps all items of the list and adds them to itself

static JsonDtoCollection FromJson(string) // => Reads a collection of serialized
                                          //    JsonDtos and deserializes them, 
                                          //    returning a Collection

string ToJson() // => serializes itself into a json string

List<object> Deserialize() // => deserializes the wrapped objects using
                           //    JsonDto.Deserialize

List<T> Deserialize<T>()   // deserializes the as above and tries to cast to T
0
source

All Articles