someone, please tell me the most straightforward syntax to remove a property from a c# object. I don't know why it is not clear on the internet.
{
"id": 1,
"name": "string",
"email": "string",
"cities": []
}
this is the response I get upon calling the get API. I want to remove the cities array, but I don't know why everything is so complicated in c#. I expect a magical short syntax like delete(in JS). Remember that this response is a dbContext response, not a standard object(DTO).
if you going to deserialize json, you can just create a class without cities property
public class Data
{
public int id { get; set; }
public string name { get; set; }
public string email { get; set; }
}
or if you can not change the class properties, just add an ignore attribute
using Newtonsoft.Json;
public class Data
{
.....
[JsonIgnore]
public List<object> cities {get; set;}
}
the code
Data data= JsonConvert.DeserializeObject<Data>(json);
if you want to remove only from json
var jsonParsed = JObject.Parse(json);
jsonParsed.Properties()
.Where(attr => attr.Name == "cities")
.First()
.Remove();
json=jsonParsed.ToString();
first, you can not change the class structure in runtime in C#.
you should define new object with your properties in mind, or use dynamic-expando objects to be able to manipulate object at runtime.
if your issue is only when you want to sterilize your object you can use [JsonIgnore] Property on the model:
public class MyDto
{
public int id { get; set; }
public string name { get; set; }
public string email { get; set; }
[JsonIgnore]
public string[] cities { get; set; }
}
this will tell you serializer to skip that property.
if you want to convert ur already define class to a dynamic object there are lots of ways.
you can use this nugget package that I wrote which have a DeSelect() method that returns a dynamic object without the specified properties:
https://www.nuget.org/packages/linqPlusPlus/1.3.0#readme-body-tab
Related
I am trying to migrate from Newtonsoft.Json to System.Text.Json
However, I ran into a problem since I was using DefaultContractResolver.
My "custom" behaviour have these rules for property serialization:
Skip property serialization if it is marked with ReadOnly attribute
Skip property serialization in case of null (this is supported)
Skip property serialization which would serialize into an empty object
Example:
class Car
{
[ReadOnly]
public string Id { get; set; }
public string Name { get; set; }
public Person Owner { get; set; }
}
class Person
{
[ReadOnly]
public string Id { get; set; }
public string Name { get; set; }
}
Now, imagine, we have this data if no rules would apply.
{
"Id":"1234",
"Name":"Skoda",
"Owner":{
"Id":"abcd",
"Name":null
}
}
Now, if I serialize the object, I would like to get this instead.
{
"Name":"Skoda"
}
In order to ignore individual properties, you need to use the [JsonIgnore] attribute along with one of these conditions:
Always;
Never;
WhenWritingDefault;
WhenWritingNull.
You can also define a default ignore condition through the JsonSerializerOptions type.
If additional behavior is needed, you should write a custom converter.
Example:
class Person
{
[JsonIgnore(Condition = JsonIgnoreCondition.Always)]
public string Id { get; set; }
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string Name { get; set; }
}
More information:
How to ignore properties with System.Text.Json
How to write custom converters for JSON serialization (marshalling) in .NET
My Identity Settings class:
public abstract class UserAccount
{
[Required]
public string Firstname { get; set; }
[Required]
public string Lastname { get; set; }
[EmailAddress]
public string Email { get; set; }
public string Password { get; set; }
[Required]
public string RoleName { get; set; }
}
public class AdministratorUserAccount : UserAccount
{
public string Company{ get; set; }
}
public class ManagerUserAccount : UserAccount
{
public string AdministratorEmail { get; set; }
}
public class IdentitySettings
{
[Required]
[MinLength(1)]
public List<UserAccount> UserAccounts { get; set; }
}
in startup.cs:
services.Configure<T>(configuration.GetSection("Identity"));
in DBInitializer, the list of UserAccounts is always empty.
var defaultUserAccountsSettings = services.GetRequiredService<IOptions<IdentitySettings>>().Value;
How to be able to get the data from appsettings.json serialized in a list of UserAccount where UserAccount can be Administrator or Manager.
It seems like the option binding doesn't know which concreate class object to create to fill up the list since UserAccount is abstract.
To make the scenario work, we need to have a way to control the creation of the object somehow.
How about putting the list in an additional json (test-data.json for example), read it by a jsonSerializer, and fill up the list:
services.AddOptions<IdentitySettings>().Configure(idSettings => {
idSettings.UserAccounts = JsonConvert.DeserialzeObject<IdentitySettings>(...); // Whatever deserializer that works.
});
Here's how to creating object with TypeNameHandling with Newtonsoft.Json: Deserialize a List<AbstractClass> with newtonsoft.json.
=====
After I read the comment, I realized you relies on Options pattern with various providers. In that case, technically, one approach could be parsing of IConfigurationSection like this:
var x = Configuration.GetSection("UserAccounts").AsEnumerable();
The result of the KeyValue pair will be a bit tedious to deal with, like:
Key
Value
UserAccount
null
UserAccount:0
null
UserAccount:0:FirstName
Mike
UserAccount:0:LastName
...
...
UserAccount:1
null
UserAccount:1:FirstName
...
...
Group it by the index will results to Group<int, IEnumerable<KeyVaultPair<string, string>>.
Create a factory method like static bool TryBuildAccount(IEnumerable<KeyValuePair<string,string>> input, out UserAccount account); to create one object by 1 group.
Then, the question is, it it really worth it? Will it become too complex when there's change to the Account class.
I would probably take Hassan Monjezi's suggestion unless there's better way that doesn't require that much tedious code.
I don't know how to phrase this question properly but basically I haven an ASP.Net Application. I send the following request to the controller from my view:
http://localhost:59112/Contacts/IndexJson?current=1&rowCount=50&sort%5BLastName%5D=desc&searchPhrase=&_=1490960196673
I have written two classes that are not working 100% as follows for a structure for this request data:
public class RequestData
{
public int current { get; set; }
public int rowCount { get; set; }
public string searchPhrase { get; set; }
public IEnumerable<SortData> sortItems { get; set; }
}
public class SortData
{
public string Field { get; set; } // FIeld Name
public string Type { get; set; } // ASC or DESC
}
Then in my controller I have the following:
public JsonResult IndexJson(RequestData model)
{
/* Irrelevant code */
}
The model works and fills everything correctly except the sortItems returns null. How can I get the sortItems Field and Type defined in my class?
Since the parameter coming in from the RequestData is sort[Field]=Type.
Edit
I changed my RequestData class to this:
public class RequestData
{
public int current { get; set; }
public int rowCount { get; set; }
public Dictionary<string, string> sort { get; set; }
public string searchPhrase { get; set; }
public Guid id { get; set; }
}
Now the model holds the sort as {[Field, Type]} (an example of data).
If this is a good practice, how to I access Field and Type?
You can achieve this a number of different ways; your problem in each case was simply not following the modelbinder conventions for that data type.
First and foremost, IEnumerable is out if you intend to post back to it. It's not an indexable type, so the modelbinder will never be able to bind to it. However, using something like List instead, is just fine. Then, your param names simply need to be in the format of: ListProperty[N].Property, where N is the index. So for your situation you could have used sortItems[0].Field=LastName&sortItems[0].Type=desc, and it would have bound just fine to your model.
For using a dictionary, your names should be in the format of DictionaryProperty[N].Key and DictionaryProperty[N].Value, where again, N is the index. In your scenarion that would look like sort[0].Key=LastName&sort[0].Value=desc.
I have:
public Class City
{
public long ID { get; set }
...
public State State { get; set; }
...
}
public Class State
{
public long ID { get; set; }
...
public Country { get; set; }
...
}
public Class Country
{
public long ID {get; set;}
...
}
in my code I serialize a list<Country> and list<State>, etc...
The problem is if I serialize my list of Cities I get something like this:
{
"ID": 3119841,
"Name": "A Coruna",
...
"State": {
"ID": 3336902,
"Name": "Galicia",
"Country": {
"ID": 2510769,
"Name": "Spain",
...
}
...
}
...
}
this cause memory and performance issues when deserializing due to having thousands of copies of the same country object and state object, etc... what I would like to generate is:
{
"ID": 3119841,
"Name": "A Coruna",
...
"StateID": 3336902,
...
}
and then I will link up the city to the states (which I will have linked up to the country, etc.)
If I use the Ignore flag (JsonIgnoreAttribute) on the fields in the state and country classes, then I will not be able to Serialize them (I think)...
How do I achieve what I am after? (I am currently using Json.NET, but am happy to use anything that will accomplish the goal.)
To exclude a child structure from being serialized, you can use the [JsonIgnore] attribute:
public class City
{
public long ID { get; set }
...
[JsonIgnore]
public State State { get; set; }
...
}
If you want to flatten the structure, things become more complex. Your options are:
Create an intermediate flattened structure, as the result of e.g. a Linq projection.
Create a custom contract resolver for your structure, an example that may provide some inspiration on how to achieve this can be found in this question: How to flatten a referenced object into two json.net properties on the referer?
Expose the additional properties of your State class that you want to "flatten" in the City class as properties:
public long StateID { get { return State.ID; } }
Note that some frameworks will also require you to add the [ScriptIgnore] and/or [NonSerialized] attributes, in addition to or as alternatives of the [JsonIgnore].
You add [NonSerialized] attribute on top of that field.
To have a plain object (no childs), you can create a model for that object and map the required properties.
public class City
{
public long ID { get; set }
...
[NonSerialized()]
public State State { get; set; }
...
}
To have a plain object (no childs), you can create a model for that object and map required properties (only the properties you need).
public class CityModel
{
public long ID { get; set }
public string Name { get; set; }
...
public long StateID { get; set; }
...
}
Now we map the required properties. (this can be in a function that you can use when you want)
var cityModel = new CityModel {
ID = city.ID,
Name = city.Name,
...
StateID = city.State.ID
...
}
You can ignore the State property using JsonIgnore and have an additional property called StateID which gets its value from the State object.
public Class City
{
public long ID { get; set }
...
public int StateID
{
get
{
return State.ID;
}
}
[JsonIgnore]
public State State { get; set; }
...
}
I believe your most appropriate solution is follows; first, add all the required attributes to refuse serialization on your State object (which set you use totally depends on what serailizer you use):
JsonIgnore: http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonIgnoreAttribute.htm
ScriptIgnore: https://msdn.microsoft.com/en-us/library/system.web.script.serialization.scriptignoreattribute%28v=vs.110%29.aspx
NonSerialized (fields only): https://msdn.microsoft.com/en-us/library/system.nonserializedattribute%28v=vs.110%29.aspx
After doing so, I recommend you add a property that can manipulate the state object by ID:
public class City
{
public long ID { get; set; }
...
[JsonIgnore, ScriptIgnore]
public State State { get; set; }
public long StateID
{
get { return State.ID; }
/* Optionally include a set; some JSON serializers may complain in
absence of it, up to you to experiment with */
set { State = new State(value); }
}
...
}
This completely preserves your structure, and a well-designed constructor in State can handle accepting an Id and building a State object from it. If you can't build a State object from Id alone, and your JSON Serializer requires a set mutator on it, then you could simply empty the body of it.
You can expand this to your other objects as well:
public class State
{
public long ID { get; set; }
...
[JsonIgnore, ScriptIgnore]
public Country Country { get; set; }
public long CountryId
{
get { return Country.Id; }
set { Country = new Country(value); }
}
...
}
The major advantage to this model, is that if you do it correctly and design State and Country appropriately, your JSON Serializer will do all the heavy lifting.
Also, as Alex mentioned, you may also create Contract Resolvers, though this is extra work.
This all really depends on your data set. When dealing with a large dataset, I simply use the [JsonIgnore] flag on the property. From there, I would request the cities and states async. I would put the states in a IEnumerable, and then use a LINQ query to populate the IEnumerable of cities.
Something like this:
Cities.ToList().ForEach((c) =>
{
c.State= States.FirstOrDefault(x => x.Id == c.StateId);
});
Also, I tend to use virtual properties to reference other objects like State.
Something like this:
public class City
{
public int Id { get; set; }
public string Name { get; set; }
[Required]
public int StateId { get; set; }
[JsonIgnore]
[ForeignKey("StateId")]
public virtual State State { get; set; }
}
public class State
{
public int Id { get; set; }
public string Name { get; set; }
}
If I have a localdb at my disposal, then I would use a different solution.
If it's a small enough dataset, I just serialize the whole object and let JSon.Net do the heavy lifting.
I'm pretty sure you cannot use [NonSerialized] with a custom class property. At least, it threw an error on my-side.
You can use [ScriptIgnore]:
public Class City
{
public long ID { get; set }
...
[ScriptIgnore]
public State State { get; set; }
...
}
This is a follow on from Dealing with fanart.tv webservice response JSON and C#
So for artists you get a response where the main element is named the same as the artist (hence you call the webservice for thumbs for Metallica the root it called Metallica, you call it for Megadeth is is called Megadeth)
The previous question resolves that but the next stage down is albums which ends up containing two levels of these dynamically named elements so searching for a particular album and you get
{"Metallica":{"mbid_id":"65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab","albums":{"f44f4f73-a714-31a1-a4b8-bfcaaf311f50":{"albumcover":[{"id":"51252","url":"http://assets.fanart.tv/fanart/music/65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab/albumcover/kill-em-all-504c485914b25.jpg","likes":"2"}]}}}}
So you have the same top level artist details with the dynamic name but now you have for albums you have an element which is named after the MusicbrainzID and then the collection of thumbs.
For the artist details I defined classes
public class ArtistThumbs
{
public string Name { get; set; }
[JsonProperty("mbid_id")]
public string MusicBrainzID { get; set; }
[JsonProperty("artistthumb")]
public List<Thumb> Thumbs { get; set; }
}
and
public class Thumb
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("url")]
public string Url { get; set; }
[JsonProperty("likes")]
public string Likes { get; set; }
}
Then I can just de-serialize the artist to JSON with
var artistthumbs = JsonConvert.DeserializeObject<Dictionary<string, Artist>>(json);
question is how can I do the same for these albums? I really need to try and stick with JsonConvert.DeserializeObject if possible and really want to de-serialize to classes but I can't figure out how to model the classes
Same idea as the other question. Whenever you have dynamically changing property names for a JSON object you need to use a Dictionary. You can extend your existing classes easily enough to handle this.
First, define another class to hold the list of cover thumbs for the album:
class Album
{
[JsonProperty("albumcover")]
public List<Thumb> CoverThumbs { get; set; }
}
Then add the following to your property to your ArtistThumbs class:
[JsonProperty("albums")]
public Dictionary<string, Album> Albums { get; set; }
Then you can deserialize exactly as you have been doing:
var artistthumbs = JsonConvert.DeserializeObject<Dictionary<string, ArtistThumbs>>(json);
The Albums property now has the albums, where each key in the dictionary is the "MusicbrainzID" for the album and each value is the corresponding Album info.