数据协定序列化 - 是否可以序列化类型属性
本文关键字:序列化 类型 属性 数据 是否 | 更新日期: 2023-09-27 18:27:21
我正在努力提供通用的JSON序列化/反序列化服务作为WCF服务。
为了做到这一点,我有以下数据契约
[DataContract]
public class SerializationRequest
{
[DataMember]
public Object Data {get;set;} //Object to be serialized
[DataMember]
public string Type {get;set;} //Type of the Data object
}
我遇到的问题是我收到以下错误:
InnerException 消息是"类型'System.RuntimeType',数据协定名称为"RuntimeType:http://schemas.datacontract.org/2004/07/System"。请考虑使用 DataContractResolver 或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。 有关更多详细信息,请参阅 InnerException。
这告诉我要么需要让 DataContractJSONSerializer 知道该类型,要么该类型无法序列化。
我尝试注册对象的类型并将其添加到序列化程序"已知类型"中,但这似乎不起作用,这让我相信我的问题在于在我的 DataContract 上有一个类型类型的参数。
我怎样才能做到这一点?我需要能够调用以下代码("ish"(。
DataContractJsonSerializer serializer = new DataContractJsonSerializer(request.Type);
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, request.Data);
string json = Encoding.Default.GetString(ms.ToArray());
ms.Dispose();
return new JSONSerializationResponse() {Data = json};
编辑
我已将类型参数更改为要序列化的类型的完整限定名,但是当我在远程 WCF 服务中调用以下代码时,我仍然遇到同样的问题:
Type type = Type.GetType(request.Type);
DataContractJsonSerializer serializer = new DataContractJsonSerializer(type, new Type[]{Type.GetType(request.Type)});
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, request.Data);
string json = Encoding.Default.GetString(ms.ToArray());
ms.Dispose();
return new JSONSerializationResponse() {Data = json};
我尝试将该创建的类型添加到 DataContractJSONSerializer 的构造函数中的已知类型中,但这也不起作用......有什么想法吗?
下面是一个需要能够序列化的简单类的示例
[DataContract]
[KnownType(typeof(Person))]
public class Person
{
[DataMember]
public string Age {get;set;}
[DataMember]
public strign Name {get;set;}
}
所以现在我应该能够通过指定类型名称将其传递到我的请求对象中,然后返回此对象的 JSON 结果。
我不确定为什么您需要 JSON 中的 .NET 类型,但您可以将 Type 序列化为字符串,然后显然从字符串创建类型。
您可以使用 Type.FullName 和 Assembly.GetType("My.Type"( 获取字符串(序列化(并从名称创建 Type(反序列化(。
你把这种方式做得太难了。
鉴于以下情况:
[DataContract]
public class Person : BaseObject
{
[DataMember]
public string Age { get; set; }
[DataMember]
public string Name { get; set; }
}
[DataContract]
[KnownType(typeof(Person))]
public class BaseObject
{
}
static string Serialize<T>(T item)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));
string result;
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, item);
result = Encoding.Default.GetString(ms.ToArray());
};
return result;
}
您可以序列化人员:
var person = new Person { Name = "Me", Age = Int16.MaxValue.ToString() };
Console.WriteLine(Serialize<Person>(person));
// Produces: {"Age":"32767","Name":"Me"}
在这种情况下,序列化程序的工作基础是可以反序列化为单个已知类型。无论谁要拉回这些数据,都知道会发生什么,所以类型不会被推入。
或者,您可以序列化 BaseObject:
var person = new Person { Name = "Me", Age = Int16.MaxValue.ToString() };
Console.WriteLine(Serialize<BaseObject>(person));
// Produces: {"__type":"Person:#ConsoleApplication6","Age":"32767","Name":"Me"}
在这里,序列化程序看到您正在提供一个派生类型,但该类型是"已知"(即两端都知道预期的可能类型(。因此,它使用类型提示进行序列化。您不需要再执行任何操作。框架会为您处理所有操作。
将 KnownType 放在任何地方可能会很痛苦,所以这就是 DataContractJsonSerializer 构造函数的其他重载派上用场的地方,因此您可以在运行时而不是通过属性指定它们。
希望有帮助。
不能使用Type
本身,因为在运行时它将是RuntimeType
的实例 - 它是内部类,因此不能添加到ServiceKnownType
属性中(或者更准确地说 - 不能由 WCF 使用的DataContractSerializer
序列化(。
应考虑将类型的程序集限定名称序列化为简单字符串。这将允许您在客户端重新创建类型:
[DataContract]
public class SerializationRequest
{
// ...
[DataMember]
public string TypeName {get;set;}
}
// ...
var type = Type.GetType(response.TypeName);
var serializer = new DataContractJsonSerializer(type);