我正在努力提供通用的JSON序列化/反序列化服务作为WCF服务。
为了做到这一点,我有以下DataContract
[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消息是'Type'System.RuntimeType',数据协定名称为'RuntimeType:http://schemas.datacontract.org/2004/07/System'不是预期的。考虑使用DataContractResolver或将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用KnownTypeAttribute属性或将它们添加到传递给DataContractSerializer的已知类型列表中。有关详细信息,请参阅InnerException。
这告诉我,我需要让DataContractJSONSerializer知道该类型,或者Type无法序列化。
我已经尝试注册对象的类型并将其添加到Serializers“Known Types”,但这似乎不起作用,这让我相信我的问题在于我的DataContract上有一个Type类型的参数。
我怎样才能做到这一点?我需要能够调用以下代码(“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};
修改
我已将type参数更改为要序列化的类型的完全限定名称,但是当我在远程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的构造函数中的KnownTypes,但这不起作用......任何想法?
以下是一个需要能够序列化的简单类的示例
[DataContract]
[KnownType(typeof(Person))]
public class Person
{
[DataMember]
public string Age {get;set;}
[DataMember]
public strign Name {get;set;}
}
所以现在我应该能够通过指定类型名称将它传递给我的请求对象,然后返回该对象的JSON结果。
答案 0 :(得分:2)
我不确定为什么你需要JSON中的.NET类型,但你可以将Type序列化为字符串,然后显然从字符串创建一个Type。
您可以使用Type.FullName和Assembly.GetType(“My.Type”)来获取字符串(序列化)并从名称(反序列化)创建类型。
答案 1 :(得分:1)
你这么做太难了。
鉴于以下内容:
[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"}
此处序列化程序看到您提供的是派生类型,但该类型是“已知”(即两端都知道可能的类型)。因此它使用类型提示进行序列化。您不需要再做任何事情了。该框架为您处理所有这些。
在任何地方放置KnownTypes都会让对手感到痛苦,因此DataContractJsonSerializer构造函数的另一个重载就派上用场了,所以你可以在运行时而不是通过属性来指定它们。
希望有所帮助。
答案 2 :(得分:0)
您无法使用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);