C# Json.NET反序列化到接口实现
我正在尝试使用序列化一个类,以便通过http请求进行传输。这是一个客户端-服务器测试程序,它共享一些公共类文件。这些文件是一个接口(C# Json.NET反序列化到接口实现,c#,json,interface,json.net,json-deserialization,C#,Json,Interface,Json.net,Json Deserialization,我正在尝试使用序列化一个类,以便通过http请求进行传输。这是一个客户端-服务器测试程序,它共享一些公共类文件。这些文件是一个接口(ITestCase)和该接口的实现(TestPicture,TestVideo) 在同一个应用程序中序列化和反序列化下面的testCase效果很好,可能是因为Json.NET代码都包含在一个程序集中。当我序列化testCase时,将其发送到服务器,然后尝试反序列化,我得到了错误 “JSON'com.test.testcases.TestPicture,Graphic
ITestCase
)和该接口的实现(TestPicture
,TestVideo
)
在同一个应用程序中序列化和反序列化下面的testCase
效果很好,可能是因为Json.NET代码都包含在一个程序集中。当我序列化testCase
时,将其发送到服务器,然后尝试反序列化,我得到了错误
“JSON'com.test.testcases.TestPicture,Graphics Tester'中指定的错误解析类型。路径“$type”,第2行,位置61”
具有类型为JsonSerializationException的内部异常,带有消息
“无法加载程序集‘图形检测仪’。”
在中,生成Json时,$type值为“$type”:“Newtonsoft.Json.Samples.Stockholder,Newtonsoft.Json.Tests”。第二个参数似乎是按名称空间引用相关类,而不是按项目名称(即Graphics Tester),因为它发生在我的实例中
既然两个项目都共享必需的类,而且文件位于同一名称空间中,为什么Json.NET要查找程序集而不是类本身
下面是我的代码的框架;由于细节对解决问题没有帮助,所以建议使用细节。显示的是接口以及该接口的两个实现。还显示了序列化和反序列化操作以及生成的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
//}
我的解决方案:
有一个比我想象的更简单的解决方案。这不是最优的,但确实有效。我更倾向于把它归类为一种变通方法或黑客。通过更改项目属性并将程序集名称设置为在两个项目中相同,它将查找项目中已包含的类,从而创建Json字符串指定的对象。使用
$type
编码完全限定的类型名称,如果客户机和服务器不使用同一个项目来定义这些类型(即,如果每个项目都自己定义类型而不是引用公共程序集),则它们之间的差异将有所不同
在您的情况下,在客户端中,完全限定的名称是com.test.testcases.TestPicture,Graphics Tester
,但是当它到达服务器时,服务器找不到任何名为Graphics Tester
的程序集
您可以通过以下两种方法之一解决此问题:
谢谢我试图避免使用另一个二进制文件,因为我正处于一种特殊情况,即使用Mono使我的应用程序跨平台。有关我的解决方案,请参见上面的编辑。我强烈建议您使用自定义
SerializationBinder
,而不是更改程序集名称。编写一个SerializationBinder来查找仅基于类型名的类型相对容易(例如“在当前程序集中查找具有此名称的类型”),它不需要另一个二进制文件,而且与更改一个项目的名称以匹配另一个项目相比,它不太麻烦。
namespace com.test.testcases
{
interface ITestCase
{
void Run();
bool Verify();
}
}
namespace com.test.testcases
{
class TestPicture : ITestCase {}
}
namespace com.test.testcases
{
class TestVideo : ITestCase {}
}