Im using NewtonSoft linq 2 json to serialize objects from classes straight to a json string
The class object I'm using is very simple :
public class OverviewQuery
{
public string id { get; set; }
public string method { get; set; }
public string Params { get; set; }
public OverviewQuery(string sid, string smethod, string sparam)
{
this.id = sid;
this.method = smethod;
this.Params = sparam;
}
}
If I serialise this, I get the Json string :
"{\"id\":\"1\",\"method\":\"getStockItemDetails\",\"Params\":\"0000000002\"}"
The Oracle server I'm connecting to (through WebAPI's) requires me to use very very specific naming,
here it should be
"{\"id\":\"1\",\"method\":\"getStockItemDetails\",\"Params\":[\"0000000002\"]}"
Is there any way NewtonSoft implemented a way to achieve this formatting ?
Without correct formatting, the only way to send the information is through hardcoding everything..
What the serialiser is doing with your class seems straightforward.
Generally JSON-RPC services will require that the params value in the envelope be a JSON Array (for indexed parameters) or an Object (for named parameters).
Could you just change your class such that Params is an Array of String ?
Related
I have a class in C#, that has a number of variables. Let's call it "QuestionItem".
I have a list of this object, which the user modifies, and then sends it via JSON serialization (with Newtonsoft JSON library) to the server.
To do so, I deserialize the objects that are already in the server, as a List<QuestionItem>, then add this new modified object to the list, and then serialize it back to the server.
In order to display this list of QuestionItems to the user, I deserialize the JSON as my object, and display it somewhere.
Now, the problem is - that I want to change this QuestionItem and add some variables to it.
But I can't send this NewQuestionItem to the server, because the items in the server are of type OldQuestionItem.
How do I merge these two types, or convert the old type to the new one, while the users with the old version will still be able to use the app?
You are using an Object Oriented Language, so you might aswell use inheritance if possible.
Assuming your old QuestionItem to be:
[JsonObject(MemberSerialization.OptOut)]
public class QuestionItem
{
[JsonConstructor]
public QuestionItem(int Id, int Variant)
{
this.Id = Id;
this.Variant = Variant;
}
public int Id { get; }
public int Variant { get; }
public string Name { get; set; }
}
you can extend it by creating a child class:
[JsonObject(MemberSerialization.OptOut)]
public class NewQuestionItem : QuestionItem
{
private DateTime _firstAccess;
[JsonConstructor]
public NewQuestionItem(int Id, int Variant, DateTime FirstAccess) : base(Id, Variant)
{
this.FirstAccess = FirstAccess;
}
public DateTime FirstAccess { get; }
}
Note that using anything different than the default constructor for a class requires you to use the [JsonConstructor] Attribute on this constructor and every argument of said constructor must be named exactly like the corresponding JSON properties. Otherwise you will get an exception, because there is no default constructor available.
Your WebAPI will now send serialized NewQuestionItems, which can be deserialized to QuestionItems. In fact: By default, JSON.NET as with most Json libraries, will deserialize it to any object if they have at least one property in common. Just make sure that any member of the object you want to serialize/desreialize can actually be serialized.
You can test the example above with the following three lines of code:
var newQuestionItem = new NewQuestionItem(1337, 42, DateTime.Now) {Name = "Hello World!"};
var jsonString = JsonConvert.SerializeObject(newQuestionItem);
var oldQuestionItem = JsonConvert.DeserializeObject<QuestionItem>(jsonString);
and simply looking at the property values of the oldQuestionItem in the debugger.
So, this is possible as long as your NewQuestionItem only adds properties to an object and does neither remove nor modify them.
If that is the case, then your objects are different and thus, requiring completely different objects with a different URI in your API, as long as you still need to maintain the old instance on the existing URI.
Which brings us to the general architecture:
The most clean and streamline approach to what you are trying to achieve is to properly version your API.
For the purpose of this link I am assuming an Asp.NET WebApi, since you are handling the JSON in C#/.NET. This allows different controller methods to be called upon different versions and thus, making structural changes the resources your API is providing depending on the time of the implementation. Other API will provide equal or at least similar features or they can be implemented manually.
Depending on the amount and size of the actual objects and potential complexity of the request- and resultsets it might also be worth looking into wrapping requests or responses with additional information. So instead of asking for an object of type T, you ask for an Object of type QueryResult<T> with it being defined along the lines of:
[JsonObject(MemberSerialization.OptOut)]
public class QueryResult<T>
{
[JsonConstructor]
public QueryResult(T Result, ResultState State,
Dictionary<string, string> AdditionalInformation)
{
this.Result = result;
this.State = state;
this.AdditionalInformation = AdditionalInformation;
}
public T Result { get; }
public ResultState State { get; }
public Dictionary<string, string> AdditionalInformation { get; }
}
public enum ResultState : byte
{
0 = Success,
1 = Obsolete,
2 = AuthenticationError,
4 = DatabaseError,
8 = ....
}
which will allow you to ship additional information, such as api version number, api version release, links to different API endpoints, error information without changing the object type, etc.
The alternative to using a wrapper with a custom header is to fully implement the HATEOAS constraint, which is also widely used. Both can, together with proper versioning, save you most of the trouble with API changes.
How about you wrapping your OldQuestionItem as a property of QuestionItem? For example:
public class NewQuestionItem
{
public OldQuestionItem OldItem { get; set; }
public string Property1 {get; set; }
public string Property2 {get; set; }
...
}
This way you can maintain the previous version of the item, yet define new information to be returned.
Koda
You can use something like
public class OldQuestionItem
{
public DateTime UploadTimeStamp {get; set;} //if less then DateTime.Now then it QuestionItem
public string Property1 {get; set; }
public string Property2 {get; set; }
...
public OldQuestionItem(NewQuestionItem newItem)
{
//logic to convert new in old
}
}
public class NewQuestionItem : OldQuestionItem
{
}
and use UploadTimeStamp as marker to understand, what Question is it.
I have a web service which return response in JSON format as below.
{"123":{"Name":"Abcd", "Age":"30"},"231":{"Name":"xyz", "Age":"20"}, "543":{"Name":"pqr", "Age":"35"}}
I want to deserialize this response in C# and wants to display it.
How can I do with Newtonsoft.Json library.
Please help me.
I'm going to assume that "123", "231", and "543" are identifiers and not constant property names. In that case what you have is a dictionary of objects. First, define a class that maps to the object.
public class Something
{
public string Name { get; set; }
public string Age { get; set; }
}
Then deserialize into a dictionary of those objects.
var whatever = JsonConvert.DeserializeObject<Dictionary<string, Something>>(json);
I am having difficulty writing the appropriate annotations to represent data which is returned from a JSON Get request which returns data like so:
[{"ProductCode":"0129923083091","Description":"DIESEL ","SalesLitres":6058.7347,"SalesValue":6416.2000},{"ProductCode":"0134039344902","Description":"UNLEADED ","SalesLitres":3489.8111,"SalesValue":3695.7100},
...
]
(ellipsis above just indicating that I could have variable number of these items returned)
In my model class (I am using MVVM approach for a Xamarin project but that's not over relevant here) I am using annotations to represent the model attributes
namespace App8.Models
{
public class ReportRow
{
[JsonProperty("ProductCode")]
public string ProductCode { get; set; } = string.Empty;
[JsonProperty("Description")]
public string Description { get; set; } = string.Empty;
[JsonProperty("SalesLitres")]
public double SalesLitres { get; set; } = 0.0;
[JsonProperty("SalesValue")]
public double SalesValue { get; set; } = 0.0;
}
}
I would like to annote another class which shows the container/contained relationship. However, I coming unstuck as there is no JSON attribute to provide in the annotation to represent the "root" of the returned collection.
I'd have no problem mapping the JSON to an object model for any JSON arrays which are named within the returned JSON. In that case I could create another class with a named JSON attribute which contained a C# List but I am trying to provide an appropriate model mapping for JSON which returns a list of items within an unnamed array.
Any ideas how I could approach this?
To deserialize that JSON, use:
JsonConvert.DeserializeObject<List<ReportRow>>(json)
(or any variant you wish, the key here is asking to deserialize a ICollection of ReportRow. It could be your own class implementing ICollection, or any of the builtins)
The same idea follows to JsonTextReader or whatever other means of deserializing JSON.NET offers. Just use a ICollection<YourType> as target type.
I've got a RequestDto, let's say Class A Dto, it contains a self defined type property:
// C# code
public Class MyObject
{
public string A { get; set; }
public string B { get; set; }
}
public Class ADto
{
public List<MyObject> MO { get; set;}
}
When I am trying to send the Dto using Json, the Json object looks like this:
{"MO":[{"A":"String","B":"a"},{"A":"String","B":"b"}]}
but the object I am receiving will be null.
However if I change the Json string into:
{MO:[{A:"String",B:"a"},{A:"String",B:"b"}]}
I lose the quotation marks on the objects' names and it works.
The correct format of Json should include those quotation marks right?
Why is this happening?
ServiceStack does serializes and deserializes valid JSON which requires every property name to be quoted however you're saying that the text below works:
{MO:[{A:"String",B:"a"},{A:"String",B:"b"}]}
However this isn't valid JSON, it instead looks like ServiceStack's JSV Format
You haven't mentioned where you're sending the JSV Format or have provided the Raw HTTP Request (for us to work it out), but I'm assuming if you're using Postman (mentioned in your comments) than you're trying to send JSON in the ?QueryString which isn't allowed.
But ServiceStack does support sending complex object graphs on the QueryString using JSV.
Since you're sending a complex type you'd either POST the request as either JSON or www-form-urlencoded Form Data or if you want to pass it in the QueryString you need to convert it to JSV.
In future please include the Raw HTTP Request as this question lacks any context on where you're changing the JSON string, how you're trying to use it or what's actually being sent, where you're sending it to, etc - making it impossible to guess what the issue is.
Change your class to
public Class MyObject
{
public string Mobile { get; set; }
public string Name { get; set; }
}
public Class ADto
{
public List<MyObject> MO { get; set;}
}
Then your json should be
{MO:[{Mobile:"0556604",Name:"Peter"},{Mobile:"4565466",Name:"John"}]}
I am implementing a mongodb cache for this asp.net webapi output cache (I agree redis would be better / faster but for now, I need a mongodb implementation!)
Anyway,
I have a CachedItem class that holds my key / value:
[BsonIgnoreExtraElements]
public class CachedItem
{
[BsonElement("key")]
public string Key { get; set; }
[BsonElement("value")]
public object Value { get; set; }
}
Value is an object, that could be anything, we don't control that.
In one of my tests, I have a very simple poco:
public class UserFixture
{
public UserFixture()
{
Id = Guid.NewGuid();
}
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime DateOfBirth { get; set; }
}
When this is set to the Value it is serialized and persisted.
When I try to retrieve it, it fails to deserialize, as it has automatically grabbed the "Id" property.
An error occurred while deserializing the Id property of class WebAPI.OutputCache.MongoDb.Tests.UserFixture: Cannot deserialize Guid from BsonType ObjectId
Obviously, I can't decorate UserFixture
Is there any way I can tell MongoDB driver to basically serialize CachedItem.Value, as say, a string?
I could use JSON.net to do this before saving, and deserialize it on the way back out, but I was hoping to avoid this.
It's also on GitHub
That link should take you straight to the relevent commit if you'd like to try the failing test.
You can of course tell MongoDB to serialize your class as a string by building your own custom BsonSerializer. I have found it easier to inherit from their BsonStringSerializer. You also need to register that serializer with your specific type. (I suggest using a BsonSerializationProvider for that)
What you do need to think about is how to represent all your possible data as a string so you could deserialize it back to your application (Consider for example that you probably need to save the type information).