I want to create a class with an required attribute and a mapped JSON name like the following:
class MyClass {
[Required]
public string Foo {get; set;}
}
This works all fine. But combining this with an JSON annotation like the following, breaks the validation
class MyClass {
[Required]
[JsonProperty(PropertyName = "bar")]
public string Foo {get; set;}
}
Why does the behavior change here and how can I fix that?
Try this:
class MyClass
{
[JsonProperty(PropertyName = "bar", Required = Required.Always)]
public string Foo { get; set; }
}
Related
I'm developing an API with .NET core and using AutoMapper.
all the API responses will be wrapped with a data element in the JSON response like below example
GET User
{
"data" {
"id" : 1,
"user_name": "abc"
"countryr" : {
"id" : 1348,
"code" : "USA"
}
}
}
So we have an entity for User and Country
public partial class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public virtual Country country { get; set; }
}
public partial class Country
{
public int Id { get; set; }
public string Code{ get; set; }
}
To map entities to DTO we have below reponseDTO
public class GetUserDTO {
public User data {get; set;} // To wrap reponse with data
}
public class UserDto {
public int id {get; set;}
public String user_name {get; set;}
public Country country {get; set;}
}
public class CountryDto {
public int id {get; set;}
public String code {get; set;}
}
As per my understanding , I should map the entity User to the UserDTO and Country entity to CountryDTO but what about GetUserDTO class itself? it basically contains other entities so the class itself cannot be mapped to anything it acts like a container.
So below what I did so far which is not correct
public class UserProfile : AutoMapper.Profile
{
public MappingProfile()
{
CreateMap<User, GetUserDTO>();
CreateMap<User, UserDto>()
.ForMember(userDto => userDto.user_name, map => map.MapFrom(user => user.FirstName))
CreateMap<Country, CountryDto>();
}
}
Json response
{
"data" : null
}
What to do for such situations?
You should not refer your entity classes in your DTO classes. You might want to change the DTO as below.
public class GetUserDTO {
public UserDto data {get; set;} // To wrap reponse with data
}
public class UserDto {
public int id {get; set;}
public string user_name {get; set;}
public CountryDto country {get; set;}
}
public class CountryDto {
public int id {get; set;}
public string code {get; set;}
}
And then in the Mapper profile, you need to explicitly map each property as cases are different(AutoMapper will map without explicity map if the names are exactly the same. In your example, there is a case difference)
And then remove the below line from the MapperProfile as there is no mapping from the User class to GetUserDTO class. This is the reason you are not getting any output.
CreateMap<User, GetUserDTO>();
While getting the data, you should create a new instance of GetUserDTO class and set the property "data" from the result of mappaing of the User object.
This will get you the output.
I have a weird problem:
I have a class A which contains a subclass B. class A is rather complex and changes frequently. I do need only a small fraction of the properties of class A and a complete json representation of class B, to pass it on to a different service.
This looks like this
[DataContact]
public class A
{
[DataMember]
public B Inner {get; set;}
}
[DataContact]
public class B
{
[DataMember]
public int SomeThing {get; set;}
}
What I would like to achieve is this:
[DataContact]
public class ADesired
{
[DataMember]
public B Inner {get; set;}
[DataMember]
public string InnerAsJsonString {get; set;}
}
I tried the most obvious ideas (e.g. a Jsonproperty which refers to the same name, but NewtonSoft.Json refusses to make this work)
What I have tried so far:
JsonConverter, did not work at all.
JsonProperties:
[DataContact]
public class ADesired
{
[JsonProperty("Source")]
public B Inner {get; set;}
[JsonProperty("Source")]
public string InnerAsJsonString {get; set;}
}
Which does not work at runtime, since the reference to the same property is detected.
Nuclear option: Just deserialize the string twice in the controller, but this feels just wrong.
One option is to serialize it in the class
[DataContact]
public class ADesired
{
[DataMember]
public B Inner {get; set;}
public string InnerAsJsonString => Newtonsoft.Json.JsonConvert.SerializeObject(Inner);
}
If you don't care about performance, you could use JObject as the Json-Property type.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
[DatanContract]
public class ADesired
{
[JsonIgnore]
public B Inner { get; set; }
[JsonIgnore]
public string InnerJson { get; set; }
[DataMember]
[JsonProperty(nameof(Inner))
public JObject JInner
{
get => JObject.FromObject(Inner);
set { Inner = value.ToObject<B>(); InnerJson = value.ToString(); }
}
}
That way when deserializing, the actual json is saved as InnerJson and what can be, is deserialized into Inner, and when serializing back, whatever is in Inner will get serialized.
This question already has answers here:
Can I specify a path in an attribute to map a property in my class to a child property in my JSON?
(7 answers)
Closed 6 years ago.
I have some JSON with this schema:
{
"person":{
"name":"test",
"family":"testi"
},
"Employee":{
"id":54,
"department":"web development",
"skils":[{"type":"C#", "grade":"good"},{{"type":"SQL", "grade":"Expert"}}]
}
}
and I need to map this JSON to following classes:
class Employee {
public int id { get; set; }
public string Name { get; set; }
public string Family { get; set; }
public string Department { get; set; }
public Skill[] Skills { get; set;}
}
class skill {
public string Type { get; set; }
public string Grade { get; set; }
}
Now is there any way to map my JSON schema to my C# object?
I am using the Newtonsoft.Json library and am trying to use the JsonProperty attribute like this:
[JsonProperty("Person.Name")]
on my Employee class. But this does not work. Is there any way to solve this problem?
Your class is not proper for your json. You must equalize properties of class and properties of json object.
Your json has a property named person but your class does not have it.
MappedObject mappedObject = JsonConvert.DeserializeObject<MappedObject>(yourJson);
class MappedObject{
public Person person;
public Employee employee;
}
class Person{
public string name;
public string family;
}
class Employee {
public intid{get; set;}
public string deartment {get; set;}
public Skill[] skills {get; set;}
}
class skill{
public string type{get; set;}
public string grade{get; set;}
}
OR better way you can use dynamic object.
dynamic result = new ExpandoObject();
result = JsonConvert.DeserializeObject(yourJson);
I have a class Foo as follows
public class Foo
{
public ClassA A {get;set;}
public string B {get;set;}
}
public class ClassA
{
public string C {get;set;}
}
When I get a Json string (say fooJson), I want to deserialize it to a Foo object with following conditions
The object must have the property Foo.A
Foo.B is optional
Foo.A.C is optional
I tried using MissingMemberHandling = MissingMemberHandling.Error as a part of my JsonSerializerSettings. but that throws error even when Foo.B is missing.
If you want some properties to be optional and some required, the easiest way to achieve this is to mark up your classes with [JsonProperty] attributes indicating which properties are required, e.g.:
public class Foo
{
[JsonProperty(Required = Required.Always)]
public ClassA A { get; set; }
public string B { get; set; }
}
public class ClassA
{
public string C { get; set; }
}
My class definition:
[Serializable]
public class MyClass
{
[XmlAttribute(AttributeName = "ID")] //Problem is here. same attr name ID.
public int XXX_ID { get; set; }
[XmlElement(ElementName = "XXX")]
public string XXX_Value{ get; set; }
[XmlAttribute(AttributeName = "ID")] //Problem is here. same attr name ID.
public int YYY_ID { get; set; }
[XmlElement(ElementName = "YYY")]
public string YYY_Value { get; set; }
}
My XML:
<MyClass>
<XXX ID="123">Some Values</XXX>
<YYY ID="567">Some Values</YYY>
</MyClass>
My Problem:
I want to de-serialize the above XML into an object.
During the runtime, an error has occurred, it is not allowed to have same attribute name in 2 different elements and under the same root.
How to solve this problem?
P/S: I cannot change the XML, I am not the owner of it.
Thanks in advance.
To do that you either need to do the (de)serialization manually, or you need to DTO to have roughly the same layout as the xml. For example:
public class Something { // need a name here to represent what this is!
[XmlAttribute] public int ID {get;set;}
[XmlText] public string Value {get;set;}
}
then
public class MyClass {
public Something XXX {get;set;}
public Something YYY {get;set;}
}