问题描述
我通过 webapi 发送这个结构:
I'm sending this structure through webapi:
[DataContract]
public class PacketData
{
public enum Opcodes
{
Hello = 0x00,
Close = 0x01,
Serial = 0x02,
GPIO = 0x04
}
[DataMember]
public object Data { get; private set; }
[DataMember]
public Opcodes Opcode { get; private set; }
public PacketData(Opcodes opcode, object data)
{
Data = data;
Opcode = opcode;
}
}
我的问题是我在发送它时在服务器端设置我分配给数据几个类例如.自定义类 1、自定义类 2
And my problem is that I set on server side when I sending it I assign to Data few class ex. CustomClass1, CustomClass2
现在反序列化我得到的不是对象字符串,它是:
Now on deserialize I get instead of object string which is:
{
"Cmd": 5,
"BaudRates": [
2400,
4800,
9600,
19200,
38400,
57600,
115200
],
"SerialPorts": null,
"IsOpen": false,
"BaudRate": 0,
"PortName": null,
"WriteCMD": null,
"WriteDATA": null,
"Read": null
}
所以数据是字符串而不是类或C#经典对象类型还有一个问题,我不知道如何从字符串中识别它是 CustomClass1 还是 CustomClass2.
So Data is string instead of class or C# classic object typeAnd there is problem I don't know how to recognize from string if its CustomClass1 or CustomClass2.
任何想法如何解决这个问题?
Any ideas how to resolve this?
谢谢.
包括反序列化和序列化
[HttpGet("Send", Name = "Send")]
public IActionResult Send()
{
return Ok(WebAPI.Send(), HttpStatusCode.OK);
}
public IEnumerable<string> Send()
{
List<string> packets = new List<string>();
foreach (PacketData packet in StaticConfig.SendStack.ToArray())
packets.Add(JsonConvert.SerializeObject(packet));
return packets.ToArray();
}
这是反序列化:
string json = await client.GetStringAsync(new Uri("http://localhost:5000/api/Send"));
string[] jsonArray = JsonConvert.DeserializeObject<string[]>(json);
if (jsonArray.Length == 0)
Task.Delay(100).Wait();
List<PacketData> packets = new List<PacketData>();
foreach (string j in jsonArray)
packets.Add(JsonConvert.DeserializeObject<PacketData>(j));
foreach (PacketData packet in packets)
{
string p = packet.Data.ToString();
bool a = packet.Data is PacketSerialModel; // returns false
HandleReceivedData(this, new ReceivedDataArgs(packet));
}
编辑 2:那我想要什么?
EDIT 2:So what do I want?
我想将提到的字符串返回到 PacketData.Data 然后我可以使用这样的东西:
I would like to get back mentioned string into PacketData.Data then I can use something like this:
if(packet.Data is CustomClass1)
{
}
else if(packet.Data is CustomClass2)
{
var b = packetData as CustomClass2;
//...
}
目前我的 packet.Data 是字符串,我需要在这个对象属性上创建并根据 json 为它们设置值.
currently my packet.Data is string and I need to create on this object properties and set values to them based on json.
现在使用
JsonSerializerSettings()
{ TypeNameHandling = TypeNameHandling.Auto }
完美运行,但我必须替换传入的 json 字符串项目名称像下面的字符串:
Works perfectly, but I have to replace in incoming json string project namelike in following string:
["{"Data":{"$type":"Shared.PacketSerialModel, ASP_MVC","Cmd":5,"BaudRates":[2400,4800,9600,19200,38400,57600,115200],"SerialPorts":null,"IsOpen":false,"BaudRate":0,"PortName":null,"WriteCMD":null,"WriteDATA":null,"Read":null},"Opcode":2}"]
我必须将 ASP_MVC 替换为第二个项目名称,除了替换还有其他解决方法吗?
I have to replace ASP_MVC to second project name, any workaround than replace?
推荐答案
要回答您更新的问题,在不同 .Net 程序集之间交换包含 $type
信息的 JSON 数据时,如何重新映射程序集名称使用 Json.NET",您有几个选择:
To answer your updated question, "how do I remap assembly names when exchanging JSON data containing $type
information between different .Net assemblies using Json.NET", you have a few options:
最简单的方法是将相关类型提取到共享 DLL 中并从两个程序集中引用该 DLL.这样既解决了问题,又减少了代码重复.
The simplest would be to extract the types in question into a shared DLL and reference that DLL from both assemblies. This solves the problem and also reduces code duplication.
如果您不能这样做,您将需要编写自己的SerializationBinder
,可能继承自Json.NET的DefaultSerializationBinder
,如文档中所述:自定义 SerializationBinder.如果您的类不是通用的,可以简单地重新映射assemblyName
:
If you cannot do this, you will need to write your own SerializationBinder
, probably inheriting from Json.NET's DefaultSerializationBinder
, as is described in the documentation: Custom SerializationBinder. If your classes are not generic, can simply remap the assemblyName
:
public class SimpleAssemblyMappingSerializationBinder : DefaultSerializationBinder
{
readonly string oldAssemblyName;
readonly string newAssemblyName;
public SimpleAssemblyMappingSerializationBinder(string oldAssemblyName, string newAssemblyName)
{
this.oldAssemblyName = oldAssemblyName;
this.newAssemblyName = newAssemblyName;
}
public override Type BindToType(string assemblyName, string typeName)
{
if (assemblyName == oldAssemblyName)
assemblyName = newAssemblyName;
return base.BindToType(assemblyName, typeName);
}
}
有关类似的绑定器,请参阅使用 TypeNameHandling.All 处理命名空间更改.
For a similar binder, see Handling namespace changes with TypeNameHandling.All.
但是如果你的类是通用的(例如,如果Data
有时是一个List
),你将需要解析类型名称中的 通用参数.有关如何执行此操作的想法,请参阅 如何为二进制格式化程序创建一个 SerializationBinder 来处理类型从一个程序集和命名空间到另一个程序集和命名空间的移动.这个问题是关于 BinaryFormatter
但答案也适用于 Json.NET.
But if your classes are generic (for instance, if Data
is sometimes a List<CustomClass3>
), you will need to parse the generic parameters inside the type name. For an idea of how to do this see How to create a SerializationBinder for the Binary Formatter that handles the moving of types from one assembly and namespace to another. That question is about BinaryFormatter
but the answer applies to Json.NET also.
要完全省略程序集名称和命名空间,您可以使用 用于对象数据类型的 Json 序列化,用于序列化和反序列化.
To omit the assembly name and namespace entirely, you could use the binder from Json serialization for Object Data Type for both serialization and deserialization.
最后,您可以考虑切换到 DataContractJsonSerializer
它通过使用合同名称而不是原始 .Net 类型名称间接交换类型信息.虽然数据契约序列化程序通常不如 Json.NET 灵活,但它基于契约的类型信息交换可能更适合这种情况.参见例如 How to deserialize JSON with unnamed collection使用 DataContractSerializer 的类型.
Finally, you could consider switching to DataContractJsonSerializer
which exchanges type information indirectly by using contract names rather than raw .Net type names. While the data contract serializer is generally less flexible than Json.NET, its contract-based exchange of type information may be more suitable in this case. See for instance How to deserialize JSON with unnamed collection of types using DataContractSerializer.
这篇关于JsonConverter 如何反序列化为通用对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!