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.
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 situation that I can't figure out. I have two object classes:
[Serializable]
[DataContract]
public class Instrument
{
[DataMember]
public string Name {get; set;}
[DataMember]
public string Id {get; set; }
[DataMember]
public bool HideMe {get; set;}
}
[Serializable]
[DataContract]
public class Order
{
[DataMember]
public string Code {get; set;}
[DataMember]
public string OrderId {get; set; }
[DataMember]
public Instrument Inst {get; set;}
}
My code tries to serialize a JSON message of Orders. I can see in the JSON string that instrument data exists but the serialized order objects contain blank Instrument objects.
Can anyone explain this?
Thanks for the replies. The issue was that I hadn't rebuilt and released the windows service that sends the JSON.
I'm trying to understand how to query a web service that provides information about the weather. The service outputs XML.
I am not sure how to store the retrieved information in a class. Looking on the internet there seems to be two ways of doing it.
Either this way:
class CurrentWeather
{
public string CityName { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF { get; set; }
public int WindSpeedMph { get; set; }
//Lots and lots of more weather related properties
}
Or this way:
class CurrentWeather
{
public string CityName { get; set; }
public double TemperatureC { get; set; }
public double TemperatureF { get; set; }
public double WindSpeedMph { get; set; }
public CurrentObservation(string cityName, double temperatureC, double temperatureF, double windSpeedMph)
{
CityName = cityName;
TemperatureC = temperatureC;
TemperatureF = temperatureF;
WindSpeedMph = windSpeedMph;
}
}
My question: I don't know which way to do it. Which approach is the "correct" one, and why is that the case? Why would I use one way other the other?
They are exactly the same way to store data, the only difference is you added a constructor to ensure all the parameters are filled when you instance the class.
But it has a drawback, a class without an empty constructor cannot be instantiated by a serializer.
Why I say that? Because if you are receiving an XML well formed and you code your class structure as the data in that XML, you can use an XmlSerializer to deserialize the XML into an instance of that class without parsing the XML or filling the class properties.
The second is probably heading more the right way to support deserialization, but I'd probably consider breaking the data up a bit. Keep the data encapsulated so related data stays together. Your exact structure is up to you, but I'd probably break down something like:
public class CurrentConditions {
public City CurrentCity { get; set;}
public Temperature[] TemperatureReadings {get; set;}
public Wind[] WindCondtions {get; set;}
}
public class City {
public string Name {get; set;}
}
public enum TemperatureScale { Celsius, Fahrenheit }
public enum SpeedScale { MPH, KPH }
public class Temperature {
public int Degrees {get; set;}
public TemperatureScale Scale {get; set;}
}
etc.
It keeps the data organized. Allows you to only pass around and/or update the particular details you need to if you're making changes, etc.
If you posted the XML I'd have a better feel for how you could map the elements of the XML to objects.
I am trying to convert the following json into a domain object .
JSON:
[{"name":"McDonalds","deals":[{"desc":"Onion Rings free with Double Cheese burgers"}],"geometry":{"lat":13.073412,"lng":80.221393}},{"name":"JusSportz","deals":[{"desc":"20% off on Wilson Rackets"}],"geometry":{"lat":13.073231,"lng":80.221181}}]
Model:
[DataContract]
public class Deal
{
[DataMember(Name="name")]
public string Store { get; set; }
[DataMember(Name="deals")]
public Offer[] Offers {get; set;}
[DataMember(Name="geometry")]
public GeoCoordinate Location { get; set; }
}
[DataContract]
public class Offer
{
[DataMember]
public string deal;
}
I tried the DataContractJsonSerializer that is in the System.Runtime.Serialization.Json namespace and there is apparently no way to convert a string into an object. Are there any other libraries which allow me to get this done? Or is there a way to get this done using this library (by converting the Json string to some intermediate format.)?
Here's how I deserialize JSON back to my domain objects.
using (var reader = new MemoryStream(Encoding.Unicode.GetBytes("YourStringValue")))
{
var ser = new DataContractJsonSerializer(typeof(Deal));
return (Deal)ser.ReadObject(reader);
}
Is this what you were looking for?
Try to change a bit Model:
[DataContract]
public class Deal
{
[DataMember(Name="name")]
public string Store { get; set; }
[DataMember(Name="deals")]
public Offer[] Offers {get; set;}
[DataMember(Name="geometry")]
public GeoCoordinate Location { get; set; }
}
[DataContract]
public class Offer
{
[DataMember(Name="desc")]
public string deal { get; set; }
}
When I try to serialize a populated instance of type List<C>() where:
public class A<T> : List<T>
{
[XmlAttribute("Name")]
public string Name {get; set;}
public A() {}
}
public class B
{
[XmlAttribute("Other")]
public string OtherPCO { get; set:}
}
public class C : A<B>
{
}
The serialization drops the Name property of class A but does create an array of type B with the OtherPCO property. How can I get the serializer to include Name?
Collections are serialized in a specific manner, which takes into account only the items of the collection, not the extra properties you added to the class. You need to wrap the collection in another class that is not a collection.
This should give you the desired result :
public class A<T>
{
[XmlAttribute("Name")]
public string Name {get; set;}
[XmlElement(typeof(T))]
public List<T> Items { get; set; }
}