I'm trying to parse a JSON rpc 2.0 request. The standard is defined here.
I've defined my class as:
[DataContract]
public class JsonRpc2Request
{
public string method;
[DataMember(Name = "params")]
public object parameters;
public object id;
}
I then try and parse a request as follows:
JavaScriptSerializer ser = new JavaScriptSerializer();
var obj = ser.Deserialize<JsonRpc2Request>(Message.Trim());
obj.parameters is always null. I think this is because I can't define an object with the name params as per the JSON RPC spec. (My attempt is using the [DataMember(Name="params")] decoration.
How can I populate my parameters object when the JSON RPC spec calls for the name params which is a keyword in c#?
You can use the DataContractJsonSerializer:
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(JsonRpc2Request));
MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(Message.Trim()));
var obj = ser.ReadObject(stream);
and you'll want to annotate method and id with the DataMember attribute as well.
I would use Json.Net to get the full control over serialization/deserialization process
string json = #"{""method"":""mymethod"",""params"":[1,2],""id"":3}";
var rpcReq = JsonConvert.DeserializeObject<JsonRpc2Request>(json);
public class JsonRpc2Request
{
[JsonProperty("method")]
public string Method;
[JsonProperty("params")]
public object[] Parameters;
[JsonProperty("id")]
public string Id;
}
Since after completing this step, you are going to have to deal with more complex cases like
#"{""method"":""mymethod"",""params"":[{""name"":""joe""}],""id"":3}";
Related
I have an object array that contains strings and longs and this class:
public class SimpleMailAddress
{
public string Address { get; set; }
public string Name { get; set; }
public static implicit operator MailAddress(SimpleMailAddress m)
{
return new MailAddress(m.Address, m.Name);
}
}
However, when deserializing the JSON array with Json.Net, I get an anonymous type that contains Address and Name instead of a SimpleMailAddress object.
I don't want to create a strongly-typed object to deserialize into because it will not be reused and I'd have to create a lot of objects for it. Is there a way to do this with Json.Net or any other library?
This is how I'm serializing/deserializing:
var json = JsonConvert.SerializeObject(myObject);
var myObject = JsonConvert.DeserializeObject<MailMessageRequest>(json);
And MailMessageRequest:
public class MailMessageRequest
{
public string Mailer { get; set; }
public string Method { get; set; }
public object[] Args { get; set; }
}
Json does not contain any inherit knowledge about your SimpleMailAddress class. So when you are telling it to deserialize, the fact that your Args property is of type Object, the deserializer is doing the best it can (by creating an anonymous type). It just sees data, it has no knowledge that you want a SimpleMailAddress object.
Json.net has a JObject class. Try using that instead of Object for your Args parameter if the actual contents of Args may change type.
Then, as needed, you can read the data from the JObject object.
If you don't care about the actual contents of Args, then leave it as Object and ignore it.
Edit: JSon.Net can embed type information during serialization that can be used during deserialization.
Leave your Args parameter as an Object. Then use the TypeNameHandling option of All during both serialization and deserialization.
var json = JsonConvert.SerializeObject(myObject, Formatting.None,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
var myObject = JsonConvert.DeserializeObject<MailMessageRequest>(json,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
You should end up with your Args object as your desired SimpleMailAddress object.
The data contact serializers built into the.net framework have the concept of known types where you tell them what types to expect and it uses those during deserialization.
There is a built in Json data contract serializer but I'm not sure it will be compatible with your Json data, it may need to be serialized and deserialized via a datacontract serializer to work using this method.
Got it. I have to use these settings:
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full
};
var json = JsonConvert.SerializeObject(object, Formatting.None, settings);
var object = JsonConvert.DeserializeObject<MailMessageRequest>(message.Body, settings);
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.
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).
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.
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);
I've got a class which has been serialized into JSON, and which I'm trying to deserialize into an object.
e.g.
public class ContentItemViewModel
{
public string CssClass { get; set; }
public MyCustomClass PropertyB { get; set; }
}
the simple property (CssClass) will deserialize with:
var contentItemViewModels = ser.Deserialize<ContentItemViewModel>(contentItems);
But PropertyB gets an error...
We added a JavaScriptConverter:
ser.RegisterConverters(new List<JavaScriptConverter>{ publishedStatusResolver});
But when we added 'MyCustomClass' as a 'SupportedType', the Deserialize method was never called. However when we have ContentItemViewModel as the SupportedType, then Deserialize is called.
We've got a current solution which looks something like this:
class ContentItemViewModelConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
var cssClass = GetString(dictionary, "cssClass"); //I'm ommitting the GetString method in this example...
var propertyB= GetString(dictionary, "propertyB");
return new ContentItemViewModel{ CssClass = cssClass ,
PropertyB = new MyCustomClass(propertyB)}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new Exception("Only does the Deserialize");
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new List<Type>
{
typeof(ContentItemViewModel)
};
}
}
}
But we'd prefer a simpler solution of only deserializing MyCustomClass, as there are a number of other fields which are on the ViewModel, and it seems a waste to have to edit this converter every time we change/add a property....
Is there a way to Deserialize JUST PropertyB of type MyCustomClass?
Thanks for your help!
Have you considered using DatacontractJsonSerializer
[DataContract]
public class MyCustomClass
{
[DataMember]
public string foobar { get; set; }
}
[DataContract]
public class ContentItemViewModel
{
[DataMember]
public string CssClass { get; set; }
[DataMember]
public MyCustomClass PropertyB { get; set; }
}
class Program
{
static void Main(string[] args)
{
ContentItemViewModel model = new ContentItemViewModel();
model.CssClass = "StackOver";
model.PropertyB = new MyCustomClass();
model.PropertyB.foobar = "Flow";
//Create a stream to serialize the object to.
MemoryStream ms = new MemoryStream();
// Serializer the User object to the stream.
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContentItemViewModel));
ser.WriteObject(ms, model);
byte[] json = ms.ToArray();
ms.Close();
string s= Encoding.UTF8.GetString(json, 0, json.Length);
Console.ReadLine();
}
}
Add all possible classes to DatacontractJsonSerializer.KnownTypes if MyCustomClass has derivations.
For whatever it may be worth after all this time, but I stumbled over the same problem and the solution is that the Deserializer hasn't got a clue about the classes you are deserializing unless you give him the necessary information.
On the top level, it knows the type from the type parameter of Deserialize<>(). That's why your converter for ContentItemViewModel works. For nested objects, it needs __type properties and a JavaScriptTypeResolver.
var ser = new JavaScriptSerializer(new SimpleTypeResolver());
ser.RegisterConverters(myconverters);
MyClass myObject = new MyClass();
string json = ser.Serialize(myObject);
// set a breakpoint here to see what has happened
ser.Deserialize<MyClass>(json);
A TypeResolver adds a __type property to each serialized object. You can write a custom type resolver that uses short names. In this sample, I use the SimpleTypeResolver from .net that "simply" stores the fully qualified type name as __type. When deserializing, the JavaScriptDeserializer finds __type and asks the TypeResolver for the correct type. Then it knows a type and can call a registered JavaScriptConverter.Deserialize method.
Without a TypeResolver, objects are deserialized to a Dictionary because JavaScriptSerializer doesn't have any type information.
If you can't provide a __type property in your json string, I think you'll need to deserialize to Dictionary first and then add a "guessing-step" that interprets the fields to find the right type. Then, you can use the ConvertToType method of JavaScriptSerializer to copy the dictionary into the object's fields and properties.
If you need to use the JavaScriptSerializer that is provides by ASP.NET and can't create your own, consider this section from the .ctor help of JavaScriptSerializer:
The instance of JavaScriptSerializer that is used by the asynchronous communication layer for invoking Web services from client script uses a special type resolver. This type resolver restricts the types that can be deserialized to those defined in the Web service’s method signature, or the ones that have the GenerateScriptTypeAttribute applied. You cannot modify this built-in type resolver programmatically.
Perhaps the GenerateScriptType Attribute can help you. But I don't know what kind of __type Properties are be needed here.
I'm attempting to deserialize json returned from javascript via Silverlight.
Basically on the client side I am returning JSON and in my C# handler, I am getting it via ScriptObject...
I tried the ConvertTo method on the ScriptObject and still could not get anything.
How would I be able to convert a ScriptObject into a C# object that is a list of objects?
SomeCallBack(ScriptObject result) {
// convert to managed object
var objects = result.ConvertTo<List<SomeObjectClass>>(); // can't get any property from it..
// however the count is correct...
MessageBox.Show("count: " + objects.Count); // shows correct count of items
}
Silverlight contains no API to take a ScriptObject and serialise to a JSON string.
Silverlight supports JSON serialisation via the System.Runtime.Serialization.Json.DataContractJsonSerializer class found in the System.ServiceModel.Web dll.
You will need to get some javascript base JSON serialiser to convert the value you are trying to pass as a ScriptObject so that you pass a JSON string parameter instead of a ScriptObject. I believe the popular tool for this job is JQuery.
Now it looks like you were expecting a set (JSON like "[x1,x2,,,xn]") where x items are of type SomeObjectClass. You can use this little generic function to deserialise such a list :-
List<T> DeserializeJSON<T>(string json)
{
byte[] array = Encoding.UTF8.GetBytes(json);
MemoryStream ms = new MemoryStream(array);
DataContractJsonSerializer dcs = new DataContractJsonSerializer(typeof(List<T>));
return (List<T>)dcs.ReadObject(ms);
}
You would do:-
var objects = DeserializeJSON<SomeObjectClass>(someJSON);
http://json.codexplex.com/
They have a silverlight version, sounds like the Newtonsoft.Json.Linq.JObject is what you're after.
If you are returning an actual JSON object, then you can actually use the ScriptObject.ConvertTo method to deserialize the JSON object directly into a C# object. For example, you could do:
JSON Object
{ id: 0001,
name: 'some_name',
data: [0.0, 1.0, 0.9, 90.0] }
C# Object
using System.Runtime.Serialization; // From the System.Runtime.Serialization assembly
[DataContract]
public struct JsonObj
{
[DataMember]
public int id;
[DataMember]
public string name;
[DataMember]
public double[] data;
}
C# Callback
public void SomeCallback(ScriptObject rawJsonObj)
{
// Convert the object
JsonObj jsonObj = rawJsonObj.ConvertTo<JsonObj>();
}
However, if you are returning a string that represents the JSON object, as opposed to an actual JSON object, then this will not work and you will have to use an alternate deserialization method. Refer to MSDN for more details.
Hope this helps.
I've got it working just by mimicking JS objects by C# code. Interestingly enough it even allowed for objects literals to be used on a JS side (see Collection items, they are just object literals - nice move - indeed JS is the driver!).
SL Code (I pass a JS object into my SL component for processing):
[ScriptableMember()]
public string GetValue(ScriptObject o)
{
Prototype p = (Prototype)o.ConvertTo<Prototype>();
return "A";
}
JS:
control.Content.ExternalName.GetValue({ Collection: [{ a: "A1" }, { a: "A2"}] })
C#
public class Prototype
{
public List<PrototypeItem> Collection
{
get;
set;
}
}
public class PrototypeItem
{
public string a
{
get;
set;
}
}
am new to Json so a little green.
I have a Rest Based Service that returns a json string;
{"treeNode":[{"id":"U-2905","pid":"R","userId":"2905"},
{"id":"U-2905","pid":"R","userId":"2905"}]}
I have been playing with the Json.net and trying to Deserialize the string into Objects etc.
I wrote an extention method to help.
public static T DeserializeFromJSON<T>(this Stream jsonStream, Type objectType)
{
T result;
using (StreamReader reader = new StreamReader(jsonStream))
{
JsonSerializer serializer = new JsonSerializer();
try
{
result = (T)serializer.Deserialize(reader, objectType);
}
catch (Exception e)
{
throw;
}
}
return result;
}
I was expecting an array of treeNode[] objects. But its seems that I can only deserialize correctly if treeNode[] property of another object.
public class treeNode
{
public string id { get; set; }
public string pid { get; set; }
public string userId { get; set; }
}
I there a way to to just get an straight array from the deserialization ?
Cheers
You could use an anonymous class:
T DeserializeJson<T>(string s, T templateObj) {
return JsonConvert.Deserialize<T>(s);
}
and then in your code:
return DeserializeJson(jsonString, new { treeNode = new MyObject[0] }).treeNode;
Unfortunately JSON does not support Type Information while serializing, its pure Object Dictionary rather then full Class Data. You will have to write some sort of extension to extend behaviour of JSON serializer and deserializer in order to support proper type marshelling.
Giving root type will map the object graph correctly if the types expected are exact and not derived types.
For example if I have property as array of base class and my real value can contain derived child classes of any type. JSON does not support it completely but web service (SOAP) allows you to serialize objects with dynamic typing.