There is an API which I don't control, but whose output I need to consume with C#, preferably using JSON.Net.
Here's an example response:
[
{
"media_id": 36867,
"explicit": 0
}
]
I had planned to have a class like so:
class Media {
public int media_id;
public int explicit;
}
And to deserialize:
var l = JsonConvert.DeserializeObject<List<Media>>(s);
Unfortunately, "explicit" is a C# keyword, so this can't compile.
My next guess is to modify the class:
class Media {
public int media_id;
public int explicit_;
}
... and somehow map the response attributes to the C# attributes.
How should I do that, or am I totally going at this the wrong way?
Failing that, I'd be OK to just plain ignore the "explicit" in the response, if there's a way to do that?
Haven't used JSON.Net, but judging by the docs here, I figure you just need to do what you'd do with XmlSerialization: Add an attribute to tell how the JSON property should be called:
class Media {
[JsonProperty("media_id")]
public int MediaId;
[JsonProperty("explicit")]
public int Explicit;
}
C# lets you define members with reserved word names (for interoperability cases exactly like this) by escaping them with an #, e.g.,
class Media {
public int media_id;
public int #explicit;
}
Not sure how this plays with JSON.Net, but I would imagine it should work (since the # is an escape and not actually part of the field name).
The following code worked for me.
class JsonRpc {
public string id;
public string method;
public string[] #params;
}
JsonConvert.DeserializeObject<JsonRpc> (data)
Thanks everyone
Related
I think I have quite a unique problem here, where the developer of an API I need to utilize did something I don't quite understand. Yet I have to deal with it.
It is probably the best to explain the problem by showing an example:
{
"type": "type-A",
"value": "{'propA': 'type-A specific element', 'propA2': 'another typeA specific element'}"
}
We are dealing with a quite normal REST API, where the response is a json string - nothing too special. Because of some abstraction going on within the API, there is a type and a value field in each response. Depending on the type, the value will have differently structured content. Also nothing too special.
The problem is now that the content in the value field is not just a normal json object, but a string containing a json object. Therefore deserialization with JsonConvert.DeserializeObject<TargetType>(jsonString) fails with the exception
Newtonsoft.Json.JsonSerializationException: Error converting value
"{'propA': 'type-A specific element', 'propA2': 'another typeA
specific element'}" to type 'My.Project.TargetType'.
Is there any neat built-in support in the json.net library I might use to counter this issue or do I have to go a manual route and fix the json or the deserialization in some other way?
Edit: to give a bit more context: The API does indeed try to abstract its interface with equal requests and responses, but I am still able to request very specific responses in my code. Therefore I make use of a generic class which contains the common properties and a generic type for the value like so:
public class Response<TValue>
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("value")]
public TValue Value { get; set; }
}
In fact, the type isn't even relevant for me, because I know beforehand which type I will receive as response (due to my specific request). Therefore I am also able to determine the response type of value. My actual deserialization looks like this JsonConvert.DeserializeObject<Response<TargetType>>(jsonString).
Yet I did not find a neat way of parsing my value together with the Response object. Any suggestions are highly appreciated.
No, in your case you just need two steps:
public class RootObject
{
public string type {get;set;}
public string value {get;set;}
}
RootObject r = JsonConvert.DeserializeObject<RootObject>(json);
And then, depending on the type, deserialize the other object:
if (r.type == "typeA")
{
TypeA t = JsonConvert.DeserializeObject<TypeA>(r.value);
}
If all types share some common properties, you might put them in an interface or base class. This will also ease reusing the deserialized class.
I solved the problem myself by using a built-in which calls a method after deserialization of the object itself.
public class Response<TValue>
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("value")]
private string ValueString { get; set; }
public TValue Value { get; set; }
[OnDeserialized]
internal void DeserializeValue(StreamingContext context)
{
Value = JsonConvert.DeserializeObject<TValue>(ValueString);
}
}
This allows me to simply call JsonConvert.DeserializeObject<Response<TargetType>>(json), where it will first deserialize the Response and after that the value property will be deserialized to TargetType.
I have a method with the following signature:
bool DoSomething();
I want to change it to this:
bool DoSomething(IList<int> newIDs);
The boolean and the list of IDs are not related to each other. The new method contains an extra output that contains the list of new IDs. Is this bad practice? What is the right way to return multiple values in this situation?
You could also "wrap" all the return values inside an object:
public class Payload
{
public List<int> NewIDs { get; set; }
public bool Status { get; set; }
}
//Use Payload class
public Payload DoSomething(...){...}
I think it's important to understand what the semantics of the returned values are before deciding on a specific pattern. If you edit your question with details, I'll provide more insight as well.
Cheers
There is a common pattern called the TryParse pattern that is used extensively within the C# Base Class Library which is basically the same as your function signature.
For example: DateTime.TryParse
public static bool TryParse(
string s,
out DateTime result
)
I think it is fine to use this provided you include the 'out' keyword.
Edit:
Also give the function a name that makes it clear why it returns a null.
I'm pretty sure an enum isn't what I want. What I want is a list of named items
CustomerLookup = "005",
CustomerUpdate = "1010"
The "005" and "1010" aren't my values, they are the values I need to send to a 3rd party that I have no control over. There are close to 500 of them. I just want my code to look nice.
Instead of
SendRequest("005");
I'd rather see
SendRequest(RequestType.CustomerLookup);
Anyone have any self-documenting ideas without getting all crazy in the code?
Anything wrong with:
public static class RequestType
{
public static readonly string CustomerLookup = "005";
// etc
}
or
public static class RequestType
{
public const string CustomerLookup = "005";
// etc
}
? Or if you want more type safety:
public sealed class RequestType
{
public static readonly RequestType CustomerLookup = new RequestType("005");
// etc
public string Code { get; private set; }
private RequestType(string code)
{
this.Code = code;
}
}
That will basically give you a fixed set of values (the constructor is private, so outside code can't create different instances) and you can use the Code property to get at the related string value.
How about using some kind of associative array?
The way you are already doing it seems right to me.
You are clearly defining the requesttype values in your code without ambiguity and when you come to use them you have intellisense on your side.
I think the real issue is how to get the 500 values into your code without any tyypos!
In my solution, I have created public class to store value and already declare [DataContract/DataMember] attribute.
For example,
[DataContract]
public class MeterSizeInfo
{
string _meterSizeId;
[DataMember(Order = 1)]
public string MeterSizeId
{
get { return this._meterSizeId; }
set { this._meterSizeId = value; }
}
string _meterSizeName;
[DataMember(Order = 2)]
public string MeterSizeName
{
get { return this._meterSizeName; }
set { this._meterSizeName = value; }
}
}
Then I need to add another public method exposing to entire project.
I wonder I have to add [DataMember(Order = 3)] for it or not.
[DataMember(Order = 3)] //<--- must declare or not?
public string DoSomething()
{
// do something...
}
I understand that if I want to use serializer in protobuf-net to serialize my data stored in, I have to declare those attribute. but I'm not sure about that on method.
please help.
Thank you in advance.
protobuf-net is a value serializer; it doesn't know anything about methods, except for properties. If you use the same (or compatible) type, then the method will be present automatically, but this is nothing to do with protobuf-net (or any other serialization).
Re the topic of adding attributes; with the current release it generally needs something to know which properties to serialize (and more importantly: with what identifiers). There is an implicit mode, but I don't recommend it unless you know you aren't going to be ever changing the type again. Ever. At all.
In "v2", you can remove the attributes; you have the option of using an external model for this, so you might have:
var model = TypeModel.Create();
model[typeof(MeterSizeInfo)].Add("MeterSizeId", "MeterSizeName");
(don't quote me on the exact API, but something like that)
You can then use model.Serialize etc
No - shouldn't be there. You can't serialise a method!
No only properties are readable and writable in that way... so you can't add the attribute for a method.
I noticed the XmlSerializer is more forgiving to adding new members, removing existing ones, etc to the serialized types.
When I did this with the BinaryFormatter, and tried to deserialize the old data, it threw an exception.
What other alternatives are there for forgiving options, i.e. one that doesn't throw an exception just uses default values, skips them, etc?
Are protocol buffers forgiving in this regard?
You mention binary, and indeed BinaryFormatter is very brittle here. The problem is that BinaryFormatter is type and field based. Instead, you want a contract-based serializer, such as XmlSerialzier, DataContractSerializer (3.0), etc.
Or for binary, protobuf-net is a C# implementation of Google's "protocol buffers" wire format, but re-implemented along .NET lines; (note: I'm the author...).
It is (like the others) data-contract based, but instead of <CustomerName>asdasd</CustomerName> etc, it uses numeric tags to identify things instead; so:
[ProtoContract]
public class Customer {
[ProtoMember(1)]
public string Name {get;set;}
// ...
}
As you add more members you give them new unique numbers; this keeps it extensible without relying on any names etc. Plus it is very fast ;-p As with XmlSerializer, it will ignore things it doesn't expect (or it can store them for safe round-trip of unexpected data), and supports the same default things. You can even use your existing xml attributes:
[XmlType]
public class Customer {
[XmlElement(Order=1)]
public string Name {get;set;}
// ...
}
I could talk about this subject all day, so I'd better shut up before [too late].
You could inherit your class from ISerializable and define a custom GetObjectData. I haven't tested this, but such a class might be deserializable from a binary format, even if changes have since been made to the class.
EDIT
I just confirmed that this works. You can use code like the example below to explicitly define how an object is serialized and deserialized. It would then be up to you to make these methods work with older versions of your class. I tested this by serializing an instance of Cereal to a binary file, then making changes to the class and reading the file back in for deserialization.
[Serializable]
private class Cereal : ISerializable
{
public int Id { get; set; }
public string Name { get; set; }
public Cereal()
{
}
protected Cereal( SerializationInfo info, StreamingContext context)
{
Id = info.GetInt32 ( "Id" );
Name = info.GetString ( "Name" );
}
public void GetObjectData( SerializationInfo info, StreamingContext context )
{
info.AddValue ( "Id", Id );
info.AddValue ( "Name", Name );
}
}
I strongly recommend doing your own serialization so that you have well-defined file formats independent of the language schemes.
I actually find that the binary formatter is the most durable in the long run.
It provides excellent forward compatibility. That is to say, if you upgrade the file to a new version, it will not work with the old deserializer.
I generally create some simple data classes that I want to use for serialization. When i need to change the class, I implement the OnDeserialized / OnDeserializing methods. This allows the data to be upgraded.
The binary formatter does not require that you have a public setter for your properties, which to me is a big problem sometimes.
[Serializable]
public class data
{
private int m_MyInteger;
// New field
private double m_MyDouble;
[OnDeserializing]
internal void OnDeserializing(StreamingContext context)
{
// some good default value
m_MyDouble = 5;
}
public int MyInteger
{
get{ return m_MyInteger; }
set { m_MyInteger = value; }
}
}
I think the following post could help you. I also agree with others who said to write your own serializer. It is way better than generated code from xsd.exe .
See the post below:
Serialization and Deserialization into an XML file, C#
You can also look at the OptionalFieldAttribute for use with SerializableAttribute/NonSerializedAttribute and the BinaryFormatter and SoapFormatter
... version 1
[Serializable]
public class MyClass
{
public string field1;
[NonSerialized]
public string field2;
}
... version 2
[Serializable]
public class MyClass
{
public string field1;
[NonSerialized]
public string field2;
[OptionalField]
public string field3;
}