Question

I'm trying to use Json.NET to serialise a class for transfer via an http request. This is a client server test program that shares some common class files. Those files are an interface (ITestCase) and the implementations of this interface (TestPicture, TestVideo).

Serialising and deserialising testCase below within the same application works fine, presumably because the Json.NET code is all contained within the one assembly. When I serialise testCase, send it to the server, then try to deserialise, I get the error

"Error resolving type specified in JSON 'com.test.testcases.TestPicture, Graphics Tester'. Path '$type', line 2, position 61"

with an Inner Exception of type JsonSerializationException with message

"Could not load assembly 'Graphics Tester'."

In the Json.NET documentation, when the Json is generated the $type value is "$type": "Newtonsoft.Json.Samples.Stockholder, Newtonsoft.Json.Tests". The second parameter seems to reference the relevant classes by namespace, rather than by project name (namely Graphics Tester) as it is happening in my instance.

Given that both projects share the requisite classes and that the files are in the same namespace, why is Json.NET looking for the assembly rather than the class itself?

Below is the skeleton of my code; details are ommited as they don't assist with the problem. Shown is the interface, and the two implementations of that interface. Also shown are the serialisation and deserialisation operations, and the resulting Json.

ITestCase testCase = new TestPicture("test.jpg")

string json = JsonConvert.SerializeObject(testCase, Formatting.Indented, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects,
});

ITestCase instance = JsonConvert.DeserializeObject<ITestCase>(json, new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Objects,
});


//value in variable json after serialisation
//{
//  "$type": "com.test.testcases.TestPicture, Graphics Tester",
//  "filename": "test.jpg",
//  "testPoints": null
//}

Individual class files:

namespace com.test.testcases
{
    interface ITestCase
    {
        void Run();
        bool Verify();
    }
}

namespace com.test.testcases
{
    class TestPicture : ITestCase {}
}

namespace com.test.testcases
{
    class TestVideo : ITestCase {}
}

My Solution:

A simpler solution existed than I expected. It wasn't optimal, but it certainly works. I'd class it more as a workaround or a hack. By altering the Project Properties and setting the assembly name to be the same in both projects, it will find the classes that were already included in the project, and thus create the objects specified by the Json string.

Was it helpful?

Solution

The $type encodes the fully-qualified type name, which will differ between the Client and Server if they're not using the same project to define these types (i.e. if each defines the type by itself rather than referencing a common assembly).

In your case, in the client the fully-qualified name is com.test.testcases.TestPicture, Graphics Tester, but when this gets to the server the server can't find any assembly called Graphics Tester.

You can solve this in one of two ways:

  1. Define a common assembly for serializable types, and reference it from both client and server.
  2. Define the types separately both in the client and the server, and customize Json.NET's type resolving by providing a custom SerializationBinder to JsonSerializerSettings.Binder, where you could implement your own logic.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top