Reputation: 9222
I am working on providing a generic JSON serialiation/deserialization service as a WCF service.
in order to do this, I have the following 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
}
The problem I am experiencing is I am getting the following error:
The InnerException message was 'Type 'System.RuntimeType' with data contract name 'RuntimeType:http://schemas.datacontract.org/2004/07/System' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
Which tells me I either need to make the DataContractJSONSerializer aware of the type, or that Type is unable to be serialized.
I have tried registering the type of object and adding it to the Serializers "Known Types", but this doesn't seem to work, which makes me believe that my problem lies in having a parameter of type Type on my DataContract.
How can I accomplish this? I need to be able to call the following code("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};
EDIT
I have changed the type parameter to be the Full Qualified Name of the type that is to be serialized, but I am still getting the same problem when I call the following code in my Remote WCF Service:
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};
I have tried adding that created type to the KnownTypes in the Constructor of the DataContractJSONSerializer, but that is not working either...any ideas?
Here is an example of a simple class that would be called that needs to be able to be serialized
[DataContract]
[KnownType(typeof(Person))]
public class Person
{
[DataMember]
public string Age {get;set;}
[DataMember]
public strign Name {get;set;}
}
so now I should be able to pass this into my request object with specifying the type name, and then get back a JSON Result of this object.
Upvotes: 1
Views: 9142
Reputation: 7264
You're making this way too hard.
Given the following:
[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;
}
You can serialise a Person:
var person = new Person { Name = "Me", Age = Int16.MaxValue.ToString() };
Console.WriteLine(Serialize<Person>(person));
// Produces: {"Age":"32767","Name":"Me"}
In this case the serialiser is working on the basis that the can be deserialised to a single known type. Whoever is going to be pulling this data back out knows what to expect, so the type does not get pushed in.
Or you can serialize a BaseObject:
var person = new Person { Name = "Me", Age = Int16.MaxValue.ToString() };
Console.WriteLine(Serialize<BaseObject>(person));
// Produces: {"__type":"Person:#ConsoleApplication6","Age":"32767","Name":"Me"}
Here the serialiser sees that you're providing a derived type but that type is 'Known' (i.e. both ends know the possible types to expect). So it gets serialized with the type hint. You don't need to do anything more. The framework handles it all for you.
Putting KnownTypes everywhere can be a pain in the butt, so that's where the other overload for the DataContractJsonSerializer constructor comes in handy, so you can specify them at runtime rather than via attributes.
Hope that helps.
Upvotes: 1
Reputation: 6813
I'm not sure why you need the .NET type in JSON, but you can serialise the Type to a string and then obviously create a Type from a string.
You can use the Type.FullName and Assembly.GetType("My.Type") to get the string (serialise) and create Type from the name (deserialise).
Upvotes: 2
Reputation: 31444
You can't work with Type
itself, because at runtime it will be an instance of RuntimeType
- which is internal class and therefore cannot be added to ServiceKnownType
attribute (or to be more precise - cannot be serialized by DataContractSerializer
used by WCF).
You should considering serializing type's assembly qualified name as a simple string. This will allow you to recreate type on client side:
[DataContract]
public class SerializationRequest
{
// ...
[DataMember]
public string TypeName {get;set;}
}
// ...
var type = Type.GetType(response.TypeName);
var serializer = new DataContractJsonSerializer(type);
Upvotes: 0