Convert a POCO to json using only certain fields - c#

I have an object, Project, that contains many fields, some complex some not. It is an EF class, so I can't edit it to add attributes.
I just want to generate a JSON object containing 2 of the fields (one int (id) and one string (name))
I'd hate to create another ViewModel just for this...
In my viewmodel I have a List<Project>. Is there a way to use HTML helpers to get a JSON representation of only the properties I choose without using attributes?
Here is an example of the Project class:
public class Project
{
public int Id {get; set; } <-- Serialize this
public string Name { get; set; } <-- Serialize this
public Object AnotherObject [ Get; Set; } <-- Ignore this
....
}
I'd like it to become:
[{"id":"27","name":"test1"},{"id":"34","name":"test2"},{"id":"35","name":"test3"}]
The ultimate goal here to is output the json directly to the view as a var so that it can be used in building a JsGrid.
If there is a way to do it with Html helpers, that would be great.
Thanks!

Json.NET has a great built in ignore feature. If you tag the Property you want to exclude with the [JsonIgnore] attribute, the serializer will not serialize that property.
[JsonIgnore]
public bool IsValid { get; set; }

Related

Convert json to C# classes with generic property

I have json data as below:
{
status: "success",
data: {
custid1: 723,
custid2: 670,
custid3: 430
}
}
As per https://json2csharp.com/, C# classes should be like below:
// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse);
public class Data {
public int custid1 { get; set; }
public int custid2 { get; set; }
public int custid3 { get; set; }
}
public class Root {
public string status { get; set; }
public Data data { get; set; }
}
But I dont like Data class above, it has custid1, custid2 as hard coded. I know here json data is like that so classes are generated accordingly but can we make some generic design which can parse below line?
var result = JsonConvert.DeserializeObject<Root>(json);
I feel that tools like Json2CSharp.com are only intended for scaffolding and prototyping rather than for directly-usable C# code. So go ahead and use it to quickly create initial code for your project, but you likely will need to tweak it for production use - in this case one of those tweaks you need to make is to change data: entry in the Root DTO class from having its own class Data to being a Dictionary<String,Int32> instead so that it can accommodate the dynamic nature of the data: property in production JSON data.
Side-note: You should use PascalCase for all class properties in your C# code - but you can configure your JSON serializer to automatically map the camelCase properties in the JSON.
If you're using Newtonsoft.Json then use CamelCaseNamingStrategy or set an explicit [JsonProperty( "camelCaseName" )]. You don't even have to do this manually because JSON2CSharp.com can do it automatically for you:
It's in the Options menu next to the Convert button:

Deserializing an unnamed array

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.

How to ignore data in JSON.NET that changes between returns

I'm parsing JSON data return by a third party.
I have my class generated with JSON2CSharp which works for the first sample we received. I tweaked it to have some JsonProperty settings so that it doesn't require certain properties that are not always present.
Now I received more samples and one of the datablobs changed format
from needing
public Translations Translations { get; set; }
to
public List<Translations> Translations { get; set; }
The blob however is information we do not need, for both performance and not having to deal with that and other pieces of information we do not need changing format, it would be ideal to just ignore it when deserializing it.
Now the real question is, should "JsonIgnore" just ignore the entire blob of data irregardless if it is in a different format then defined in the class? Or do I have to program around that?
So if I do
[JsonIgnore]
public string Translations { get; set; }
will it also ignore Translations when it gets sent a list or an object?
Can I use the same syntax with JsonIgnore as I can with JsonProperty and just say
[JsonIgnore(PropertyName = "translations")]
or does JsonIgnore just toss out anything it receives?
Additionally question:
Is it convention that when there are no translations, I get:
"translations":[]
and when there are translations I get:
"translations":{"CA":"blabla","DD":"C : blablah"}
Or is this likely a bug in the third party's website?
ADDED:
1: The Translations can switch between string, list and object between every fetch of the JSON.
2: For using DataMembers ignoring everything I don't actually need, in a class with subclasses, do I have to tell it that the subclass is [DataMember] or the subclasses properties are [DataMember]?
I would explicitly specify exactly the properties I wanted serialized/deserialized in my data class using DataContractAttribute and DataMemberAttributes for the members you actually want to deserialize.
This is opt in, so no attempt is made to shoehorn anything extra in your JSON into your data class, and anything extra in your data class doesn't show up in serialized JSON.
So assuming your class right now looks like this:
class MyData {
// Old member
// public Translations Translations { get; set; }
public List<Translation> Translations { get; set; }
public string ThisShouldBeSerialized { get; set; }
}
You can change it so things that you want serialized are explicitly marked as such, and anything not marked for serialization is ignored by default:
[DataContract]
class MyData {
// Old member
// public Translations Translations { get; set; }
public List<Translation> Translations { get; set; }
[DataMember]
public string ThisShouldBeSerialized { get; set; }
}
And then:
var myJSON = #"{
'ThisShouldBeSerialized': 'test',
'Translations': {
'Some' : 'Strange',
'Data' : 'Blob'
}
}";
var result = JsonConvert.DeserializeObject<MyData>(myJSON);

Deserializing of Google's Translate API result in C#

I'm trying to deserialize Google's Translate API JSON response into an C# object using JavaScriptSerializer. However, it always says Type 'TranslateAPI.Models.Translations' is not supported for deserialization of an array.. I double checked whether I have correctly created models for this object and it seems right. Here are my models:
TranslateResult
public TranslateData data { get; set; }
TranslateData
public Translations translations { get; set; }
Translations
public TranslatedText[] translatedText { get; set; } // I have also tried List<TranslatedText> which also doesn't work
TranslatedText
public string translatedText { get; set; }
The json returned from Google looks like this:
{data: {
translations: [
{translatedText: "Hello world"}
]
}
Any idea what I'm doing wrong?
Thanks
PS. It could be useful to mention, that I'm deserializing it like so: TranslateResult translateResult = js.Deserialize <TranslateResult>(json);
I suspect you don't need the Translations class at all. You've got:
An object containing a data property
The data property value is an object containing a translations property
The translations property value is an array
Each element of the array is an object with a translatedText property
So that sounds to me like your TranslateData class should be:
TranslateData
public Translation[] translations { get; set; }
Translation // Renamed from TranslatedText
public string translatedText { get; set }
(I'd also recommend that you rename the properties to follow normal C# naming conventions, and then apply attributes to help with the JSON conversion if you need to. I haven't used JavaScriptSerializer for a while, but I'm sure it's feasible. You shouldn't need to work with nasty property names in your C# code.)

Serialize embedded class / object independently or as string?

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).

Categories

Resources