数据协定序列化 - 是否可以序列化类型属性

本文关键字:序列化 类型 属性 数据 是否 | 更新日期: 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);