我通过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
现在在反序列化时,我得到的不是对象字符串,它是:
{rn "Cmd": 5,rn "BaudRates": [rn 2400,rn 4800,rn 9600,rn 19200,rn 38400,rn 57600,rn 115200rn ],rn "SerialPorts": null,rn "IsOpen": false,rn "BaudRate": 0,rn "PortName": null,rn "WriteCMD": null,rn "WriteDATA": null,rn "Read": nullrn}
所以数据是字符串而不是类或 C# 经典对象类型并且有一个问题,我不知道如何从字符串中识别它的自定义类 1 还是自定义类 2。
任何想法如何解决这个问题?
谢谢。
编辑:包括反序列化和序列化
[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:那我想要什么?
我想将提到的字符串返回到PacketData.Data中,然后我可以使用这样的东西:
if(packet.Data is CustomClass1)
{
}
else if(packet.Data is CustomClass2)
{
var b = packetData as CustomClass2;
//...
}
目前是我的包。数据是字符串,我需要在此对象上创建属性并根据 json 为它们设置值。
编辑3:现在使用
JsonSerializerSettings()
{ TypeNameHandling = TypeNameHandling.Auto }
工作完美,但我必须替换传入的json字符串项目名称如以下字符串:
["{"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替换到第二个项目名称,除了替换之外有什么解决方法吗?
若要回答更新的问题"使用 Json.NET 在不同 .Net 程序集之间交换包含$type
信息的 JSON 数据时,如何重新映射程序集名称",您有几个选项:
-
最简单的方法是将相关类型提取到共享 DLL 中,并从两个程序集引用该 DLL。 这解决了问题,也减少了代码重复。
-
如果你不能做到这一点,你将需要编写你自己的
SerializationBinder
,可能是从Json.NET的DefaultSerializationBinder
继承的,如文档中所述:自定义序列化绑定器。 如果你的类不是泛型的,可以简单地重新映射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 处理命名空间更改。
但是如果你的类是泛型的(例如,如果
Data
有时是一个List<CustomClass3>
(,你将需要解析类型名称中的泛型参数。 有关如何执行此操作的想法,请参阅如何为二进制格式化程序创建序列化绑定程序,该格式化程序处理类型从一个程序集和命名空间到另一个程序集和命名空间的移动。 这个问题是关于BinaryFormatter
但答案也适用于 Json.NET。 -
若要完全省略程序集名称和命名空间,可以使用对象数据类型的 Json 序列化中的绑定程序进行序列化和反序列化。
-
最后,可以考虑切换到使用协定名称而不是原始 .Net 类型名称间接交换类型信息的
DataContractJsonSerializer
。 虽然数据协定序列化程序通常不如 Json.NET 灵活,但在这种情况下,其基于协定的类型信息交换可能更合适。 例如,请参阅如何使用 DataContractSerializer 使用未命名的类型集合反序列化 JSON。