System.Text.Json Converter to change string property to float [duplicate] - c#

This question already has answers here:
Automatic conversion of numbers to bools - migrating from Newtonsoft to System.Text.Json
(1 answer)
System.Text.Json: Deserialize JSON with automatic casting
(7 answers)
Closed 12 months ago.
Given the following json document, what would be the best way to convert it to a valid object using a Converter? The trick comes in that the source json has the value property as string where it should be serialized as a float?
{
"metric": "metric",
"operator": "GREATER_THAN",
"value": "1",
"status": "OK",
"errorThreshold": "1"
}
The resulting c# object:
public class Condition
{
[JsonPropertyName("errorThreshold")]
public string ErrorThreshold { get; set; }
[JsonPropertyName("metric")]
public string Metric { get; set; }
[JsonPropertyName("operator")]
public string Operator { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("value")]
public double? Value { get; set; }
}
I'm toying here with a converter that makes use of reflection to do this, but this seems like using a shotgun to kill a earthworm.
Are there any more commonly established/recommended ways in doing this?

well one way is
public class Condition
{
[JsonPropertyName("errorThreshold")]
public string ErrorThreshold { get; set; }
[JsonPropertyName("metric")]
public string Metric { get; set; }
[JsonPropertyName("operator")]
public string Operator { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("value")]
public string Value { get; set{
Double.TryParse(value, out ValNumeric);
}; }
public double ValNumeric = 0;
}

I would never use Text.Json for something except "Hello World", but you can do it this way, you do not need any extra properties
var conditionParsed = JsonDocument.Parse(json);
var condition =conditionParsed.Deserialize<Condition>();
if (double.TryParse( conditionParsed.RootElement.GetProperty("value").GetString(),out double value))
condition.Value=value;
and change value property attribute
[System.Text.Json.Serialization.JsonIgnore]
public double? Value { get; set; }
or you can like this too
[JsonPropertyName("value")]
public string _value { get; set; }
[System.Text.Json.Serialization.JsonIgnore]
public double? Value
{
get { return double.TryParse(_value, out double val)? val:null; }
set { _value = value != null ? value.ToString(): null; }
}
but in this case you will need an extra public propery

Related

How to ignore a property from serialization but keep in for deserialization using json.net in c# [duplicate]

This question already has answers here:
Making a property deserialize but not serialize with json.net
(13 answers)
Closed 3 years ago.
How to ignore a property from serialization but keep in for deserialization using json.net in c#.
Example:
public class Foo
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("contentType")]
public object ContentType { get; set; }
[JsonProperty("content")]
public object Content { get; set; }
[JsonIgnore]
public Relationship RelationshipContent { get; set; }
[JsonIgnore]
public Domains DomainContent { get; set; }
}
in the above code i need to deserialize the "content" into the property "RelationshipContent" and "DomainContent" according to the value to the PartType property value.
Can you help me how to do it in C# using Newtonsoft.Json?
Could you have a method for the 'set' of Content and process the data into the right place.
public class Foo
{
[JsonProperty("id")]
public int Id { get; set; }
[JsonProperty("contentType")]
public object ContentType { get; set; }
[JsonProperty("content")]
public object Content { get; set {
//do something here with `value` e.g.
RelationshipContent = value; //change as required
DomainContent = value; //change as required
}
}
[JsonIgnore]
public Relationship RelationshipContent { get; set; }
[JsonIgnore]
public Domains DomainContent { get; set; }
}

Handle null values in mapper property

I'm trying to read a flat file and do some processes. To do that I've defined a mapper. That mapper will assign the values for each property. In the document, the date will be represented with yyMMdd format and it can have "" or 000000 as a null value. That mean, if the date is 6 zeros or 6 blank spaces, the output should be null. I tried to do this by defining a NullFormater. But didn't work.
This is what I've tried:
============================
public class Test : DocumentRecordBase
{
public string StorageOrganisation { get; set; }
public Guid? StorageOrganisationId { get; set; }
public string StorageDescription { get; set; }
public DateTime? PaymentDueDate { get; set; }
public decimal? DiscountRate { get; set; }
public int? MaximumDaysDiscount { get; set; }
public DateTime? DateStorageChargeCommences { get; set; }
public decimal? StorageChargePerBalePerDay { get; set; }
public decimal? PenaltyInterestRate { get; set; }
public DateTime? LotAvailableDate { get; set; }
public decimal? PostSaleRechargeRebate { get; set; }
public Test() : base()
{
}
public override T GetDocumentRecord<T>()
{
if (typeof(T) == typeof(Test))
{
return this as T;
}
return null;
}
public static IFixedLengthTypeMapper<Test> GetMapper()
{
var mapper = FixedLengthTypeMapper.Define<Test>();
mapper.Property(r => r.RecordType, 2);
mapper.Property(r => r.RecordSubType, 1);
mapper.Property(r => r.PaymentDueDate, 6)
.ColumnName("PaymentDueDate")
.InputFormat("yyMMdd")
.NullFormatter(NullFormatter.ForValue("000000")); // if the read value is "000000" or " " then should pass as null
mapper.CustomMapping(new RecordNumberColumn("RecordNumber")
{
IncludeSchema = true,
IncludeSkippedRecords = true
}, 0).WithReader(r => r.RecordNumber);
return mapper;
}
public static bool GetMapperPredicate(string x)
{
return x.StartsWith("11A");
}
}
According to the definition of NullFormatter, (found here), you can only assign 1 fixed value. "If it is a fixed value, you can use the NullFormatter.ForValue method."
NullFormatter = NullFormatter.ForValue("NULL")
If you use "000000", then it should convert 000000 to null otherwise, spaces will be considered actual values. Any number of 0s != 6 will result in non-null value as well.
Also, please define what you mean by "But didn't work". Please provide details and errors for elaboration

JSON does not retain values after Deserialization

I want to deserialize a string which is actually an array of object, this is the output of the serialization
[
{
\"CallType\":1,\
"ExecutionStart\":\"2018-07-03T12:25:55.1919951+03:00\",\
"ExecutionEnd\":\"2018-07-03T12:25:55.3980081+03:00\",\
"UnitExecutionStart\":\"0001-01-01T00:00:00\",\
"OverallExecution\":205
}
]
This is the object to which I want do deserialize
[JsonObject]
public class PerformanceMetricsItemDtoX
{
public PerformanceMetricsItemDtoX()
{
}
public CallType CallType { get; } //=> CallType is an enum
public DateTime ExecutionStart { get; }
public DateTime ExecutionEnd { get; }
public DateTime UnitExecutionStart { get; }
public long OverallExecution { get; }
}
After deserializing
var result = value.SelectMany(item =>
JsonConvert.DeserializeObject<List<PerformanceMetricsItemDtoX>>(item));
The final object result has default values so it does not retain the value that is stored in the serialized version.
What am i doing wrong ?
Thanks
Btw I've tried using
var result = new System.Web.Script.Serialization.JavaScriptSerializer()
.Deserialize<List<PerformanceMetricsItemDtoX>>(value.FirstOrDefault());
but the output is the same.
Your PerformanceMetricsItemDtoX properties are readonly, so JsonConvert (and no one, actually) can't assign any value to them, after constructor is invoked. Use this:
[JsonObject]
public class PerformanceMetricsItemDtoX
{
public CallType CallType { get; set; } //=> CallType is an enum
public DateTime ExecutionStart { get; set; }
public DateTime ExecutionEnd { get; set; }
public DateTime UnitExecutionStart { get; set; }
public long OverallExecution { get; set; }
}

List<int> in List<object> is null on deserializing (JSON) [duplicate]

This question already has answers here:
JSON.net: how to deserialize without using the default constructor?
(6 answers)
Avoiding default constructors and public property setters
(1 answer)
Closed 4 years ago.
I deserialize a json string that was created by the serialize method.
The JSON (from the Newtonsoft library) looks like this (a little bit formatted for better reading):
{"AreaKindList":
[
{"ID":1,"Kind":"Lioncage"},
{"ID":2,"Kind":"Open-Air Enclosure"}
],
"AnimalRaceList":
[
{"ID":1,"Race":"Lion","AllowedAreaKinds":[1]},
{"ID":2,"Race":"Gazelle","AllowedAreaKinds":[2]},
{"ID":3,"Race":"Antelope","AllowedAreaKinds":[2]}
],
"AreaList":
[
{"ID":1,"AreaKindId":1,"Size":2,"AnimalList":
[
{"Name":"Leo","RaceId":1}
]
}
]}
And the classes look like this:
public class Zoo
{
public List<AreaKind> AreaKindList { get; set; }
public List<AnimalRace> AnimalRaceList { get; set; }
public List<Area> AreaList { get; set; }
}
public class AreaKind
{
public int ID { get; private set; }
public string Kind { get; private set; }
public AreaKind(int id, string kind)
{
ID = id;
Kind = kind;
}
}
public class AnimalRace
{
public int ID { get; private set; }
public string Race { get; private set; }
public List<int> AllowedAreaKinds { get; private set; }
public AnimalRace (int id, string race, List<int> areaKindIds)
{
ID = id;
Race = race;
AllowedAreaKinds = areaKindIds;
}
}
public class Area
{
public int ID { get; private set; }
public int AreaKindId { get; set; }
public int Size { get; set; }
public List<Animal> AnimalList { get; set; }
public Area(int size, int areaKindId, int id)
{
ID = id;
AreaKindId = areaKindId;
Size = size;
}
}
As you can see there is a list of numbers inside the AnimalRaceList, named AllowedAreaKinds. At this moment there is only 1 entry inside. When I use the following code to deserialize the zoo-object the zoo is completly filled (including the animal Leo with the ID of 1), but the "List AllowedAreaKinds" is completly set to "NULL". Why?
using (StreamReader reader = File.OpenText(Program.JsonFile))
{
JsonSerializer serializer = new JsonSerializer();
Zoo tempZoo = (Zoo) serializer.Deserialize(reader, typeof(Zoo));
}
I even changed the serializer against a Populate(), but that gave the same result. Anyone an idea what it could be?

JavaScriptSerializer deserialize multiple JSON arrays in single string

In short, I have a client Windows Forms app that receives a Json string from an API in the following form:
string textResult = "{"Data":[{"ID":"G0000013","M_CurBalanceOutstanding":52408.5}],"DataDetail":[{"ErrorDate":"\/Date(1410179960809+0200)\/","ErrorID":1,"ErrorInfo":"Success"}]}"
or formatted via http://www.jsoneditoronline.org/
{
"Data": [
{
"ID": "G0000013",
"M_CurBalanceOutstanding": 52408.5
}
],
"DataDetail": [
{
"ErrorDate": "/Date(1410164281557+0200)/",
"ErrorID": 1,
"ErrorInfo": "Success"
}
]
}
I am trying to de-serialize it like this:
var deserializer = new JavaScriptSerializer();
List<MatterDetailBalOutstanding> results = deserializer.Deserialize<List<MatterDetailBalOutstanding>>(textResult);
where textresult is my JSon string.
I have the following classes:
[DataContract]
class MatterDetailBalOutstanding
{
[DataMember]
public string ID { get; set; }
[DataMember]
public decimal M_CurBalanceOutstanding { get; set; }
[DataMember]
public List<MatterReturnStatusDetails> ErrorData;
public MatterDetailBalOutstanding(string _ID, decimal _M_CurBalanceOutstanding, List<MatterReturnStatusDetails> _ErrorData)
{
ID = _ID;
M_CurBalanceOutstanding = _M_CurBalanceOutstanding;
ErrorData = _ErrorData;
}
}
and:
[DataContract]
class MatterReturnStatusDetails
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Info { get; set; }
[DataMember]
public DateTime Date { get; set; }
public MatterReturnStatusDetails(int _ID, string _Info, DateTime _Date)
{
ID = _ID;
Info = _Info;
Date = _Date;
}
}
I just cannot get it to work? To my understanding it is possible to de-serialize a string containing two JSon arrays. I have read a ton of threads, and a lot of them suggest using another serializer. I have to go with JavaScriptSerializer though. Please could someone help with this? What am I doing wrong? Where am I missing something?
Update 1:
When I try:
MatterDetailBalOutstanding results = deserializer.Deserialize<MatterDetailBalOutstanding>(textResult);
I get the below error:
No parameterless constructor defined for type of 'ConsumeTestWCFApp.ConsumeTestWCFApp+MatterDetailBalOutstanding'.
You can use json2csharp to assist you in generating classes suitable for mapping your JSON. Here is the result :
public class Datum
{
public string ID { get; set; }
public double M_CurBalanceOutstanding { get; set; }
}
public class DataDetail
{
public DateTime ErrorDate { get; set; }
public int ErrorID { get; set; }
public string ErrorInfo { get; set; }
}
public class RootObject
{
public List<Datum> Data { get; set; }
public List<DataDetail> DataDetail { get; set; }
}
Then you can annotate and modify the generated classes further as necessary and use it in deserialization :
var result = deserializer.Deserialize<RootObject>(textResult);
This problem:
No parameterless constructor defined for type of
'ConsumeTestWCFApp.ConsumeTestWCFApp+MatterDetailBalOutstanding'.
occurs because your serialized classes do not have a default constructor. By creating a specific constructor like this:
class MatterDetailBalOutstanding
{
public MatterDetailBalOutstanding(string _ID, decimal _M_CurBalanceOutstanding, List<MatterReturnStatusDetails> _ErrorData)
{
...
}
}
you do not get a default constructor and have to add one yourself:
class MatterDetailBalOutstanding
{
public MatterDetailBalOutstanding(string _ID, decimal _M_CurBalanceOutstanding, List<MatterReturnStatusDetails> _ErrorData)
{
...
}
public MatterDetailBalOutstanding()
{
...
}
}
This may not be you biggest problem now, but I didn't see anyone answer that part of the question.

Categories

Resources