datetime field in json deserialization - c#

I have a .json like this:
[
{
"number":"00000001",
"dt_doc":"2019-09-26T17:39.000Z",
"address":"complete address"
}
]
But I've got problem with the field dt_doc, this is my deserialization code...
I have this in the main:
public override void CreateNewOutputRows()
{
String jsonFileContent = File.ReadAllText(Variables.JsonFilePath);
JavaScriptSerializer js = new JavaScriptSerializer();
List<Testata> testata = js.Deserialize<List<Testata>>(jsonFileContent);
foreach(Testata test in testata)
{
Output0Buffer.AddRow();
Output0Buffer.number= test.number;
Output0Buffer.dtdoc = test.dt_doc;
Output0Buffer.address= test.address;
}
}
and in my class Testata.cs I have defined the field in this way:
public DateTime dt_doc { get; set; }
But I got an exception on this field, probably related to 8601 standard, is there any way to solve?
This is the exception:
Error: System.FormatException: 2019-09-26T17:39.000Z it's not a valid value for DateTime. ---> System.FormatException: String not recognized as valid DateTime value.

The error is because you are missing seconds in date
"dt_doc":"2019-09-26T17:39.000Z"
should be
"dt_doc":"2019-09-26T17:39.00.000Z"
If this is intentional then you can specify the format. I have tried this using Newtonsoft.Json
public class Testata
{
[JsonConverter(typeof(DateFormatConverter), "yyyy-MM-ddTHH:mm.fffZ")]
public DateTime dt_doc { get; set; }
}
public class DateFormatConverter : IsoDateTimeConverter
{
public DateFormatConverter(string format)
{
DateTimeFormat = format;
}
}
List<Testata> testata = JsonConvert.DeserializeObject<List<Testata>>(jsonString);

you could read it in your class as a string and then:
DateTime.ParseExact(test.dt_doc,"yyyy-MM-ddTHH:mm.fffZ");

Related

Can't set TimeSpan property from JSON source C#

I have been trying to read a JSON file and deserialize it to a class object. The problem is that I am storing a TimeSpan? property of the class as string in the JSON file which doesn't get deserialized and remains null. Please find the code for reference below:
Interface:
public interface IAirport
{
.
.
.
TimeSpan? TimeOffset { get; set; }
.
.
.
}
Class :
public class Airport:IAirport{
.
.
.
private TimeSpan? _offsetTime;
public TimeSpan? OffssetTime
{
get{return _offsetTime;}
set{SetProperty<TimeSpan>(ref _offsetTime, value);}
}
.
.
.
}
This is the way I deserialize :
private static T ConvertJsonStreamToObject<T>(StreamReader fileStream)
{
JsonSerializer serializer = new JsonSerializer();
return (T)serializer.Deserialize(fileStream, typeof(T));
}
and lastly the JSON :
{
"AirportDesignation": "ZZU",
"EffectiveDate": "1901-01-01 00:00:00.0000000",
"Description": "Mzuzu",
"DescriptionShort": "Mzuzu",
"EffectiveStatus": "A",
"Country": "MWI",
"State": " ",
"LatitudeDegrees": 11,
"LatitudeMinutes": 27,
"LatitudeSeconds": 0,
"LatitudeCoordinates": "S",
"LongitudeDegrees": 34,
"LongitudeMinutes": 1,
"LongitudeSeconds": 0,
"LongitudeCoordinates": "E",
"AirportType": "A",
"TimeOffset": "00:00:00",
"IsTimeOffsetPositive": true
}
I tried the following way to set the property and use TimeSpan.Parse() to parse the string to TimeSpan but none of them worked :
private string _timeOffset;
public TimeSpan? TimeOffset
{
get { return TimeSpan.Parse(_timeOffset); }
set { _timeOffset = value.ToString(); }
}
I am out of ideas to try, any help would be appreciated.
UPDATE:
I tried #Caius Jard suggestion, getting the System.ArgumentNullException
Updated the property as below:
private string _timeOffset;
[Required]
public TimeSpan? TimeOffset
{
get { return TimeSpan.Parse(_timeOffset); }
set { SetProperty<string>(ref _timeOffset, value.Value.ToString()); }
}
Found the culprit finally, It was an attribute causing the problem. I had an interface as the base for the Airport class and it required the TimeOffset to be a [DataMember] otherwise the property isn't identified as the data member of the class.
Adding the [DataMember] attribute now sets the value.

Get JSON Data in variable when only one item is returned

I am trying to get some currency values from an api. it's returning the data in the following format:
{"PKR_PKR":{"val":1}}
I want to show this value in textbox but there's an error
"Object reference not set to an instance of object".
I've tried the following code:
try
{
string endPoint = #"http:urlhere";
string ResultJson = "";
using (WebClient wc = new WebClient())
{
ResultJson = wc.DownloadString(endPoint);
}
JsonData values = JsonConvert.DeserializeObject<JsonData>(ResultJson);
txtBalanceRate.Text = values.CurrencyValue.ToString();
}
catch (Exception ex) { }
Class code:
class JsonData
{
public object CurrencyValue { get; set; }
}
**
UPDATE
**
Note: I can not update PKR_PKR Class becuase every time the name of variable is different for different currencies i.e. it can be USD_PKR , EUR_PKR etc
How can I resolve this?
FOLLOWING IS THE UPDATED CODE:
try
{
string endPoint = #"http://free.currencyconverterapi.com/api/v5/convert?q="+ddlCurrency.SelectedValue.ToString()+"_PKR&compact=y";
string ResultJson = "";
using (WebClient wc = new WebClient())
{
ResultJson = wc.DownloadString(endPoint);
}
RootObject rootObject = JsonConvert.DeserializeObject<RootObject>(ResultJson);
txtBalanceRate.Text = rootObject.PKR_PKR.val.ToString();
}
catch (Exception ex)
{
}
public class PKRPKR
{
public int val { get; set; }
}
public class RootObject
{
public PKRPKR PKR_PKR { get; set; }
}
If you are going to have dynamic object then you should try this out
dynamic data = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
Type typeOfDynamic = data.GetType();
if( typeOfDynamic.GetProperties().Where(p => p.Name.Equals("PKR_PKR")).Any())
{
console.WriteLine(data.PKR_PKR.val);
}
else if( typeOfDynamic.GetProperties().Where(p => p.Name.Equals("USD_PKR")).Any())
{
console.WriteLine(data.USD_PKR.val);
}
else if( typeOfDynamic.GetProperties().Where(p => p.Name.Equals("EUR_PKR")).Any())
{
console.WriteLine(data.EUR_PKR.val);
}
above way is not tried and tested but you can have try like this as you json is dynamic.
Above way is checking property exist or not and get val from dynamci object
Your class structure is incorrect can you please try below class structure
public class PKRPKR
{
public int val { get; set; }
}
public class RootObject
{
public PKRPKR PKR_PKR { get; set; }
}
RootObject rootObject = JsonConvert.DeserializeObject<RootObject>(json);
Console.WriteLine(rootObject.PKR_PKR.val);
Mostly if you see above class structure , you josn each node is represent as class, but I dont go in much detail as Visual studio can do it for me.
When comes to json to object conversion ,I make use of utility provided by Visual studio. which does conversion of json string to proper class structure. here is image of it
Read how to do it full here :
Visual Studio Generate Class From JSON or XML
If you dont have visual studio with this feature you can use this online utility : json2csharp
Note: I can not update PKR_PKR Class becuase evert time the name of
variable is different for different currencies i.e. it can be USD_PKR
, EUR_PKR etc How can I resolve this?
SOLUTION
if json string {"PKR_PKR":{"val":1}} is fixed in your case, you can use following solution for any currency name you got.
static void Main(string[] args)
{
string json1 = "{ \"PKR_PKR\":{ \"val\":1}}";
string json2 = "{ \"USD_PKR\":{ \"val\":2}}";
string json3 = "{ \"EUR_PKR\":{ \"val\":3}}";
JToken token1 = (JToken)JsonConvert.DeserializeObject(json1);
Console.WriteLine(token1.First().First()["val"]);
JToken token2 = (JToken)JsonConvert.DeserializeObject(json2);
Console.WriteLine(token2.First().First()["val"]);
JToken token3 = (JToken)JsonConvert.DeserializeObject(json3);
Console.WriteLine(token3.First().First()["val"]);
Console.ReadLine();
}
I think your receiving object should contain a dictionary, not a single string:
Check this
Or you have to improve your object structure implementing a root item which contains a PKR_PKR sub object

TimeZoneInfo serialization issue c#

I had an issue serializing TimezoneInfo as it does not have a parameterless constructor. I tried to get around it by doing what was suggested here
https://social.msdn.microsoft.com/Forums/vstudio/en-US/a2bda890-41e9-47e8-b404-042d110e4f13/serializing-classes-containing-timezoneinfo?forum=netfxbcl
This is what my request object looks like
[MessageContract(WrapperNamespace = ServiceConstants.ContractNameSpaceMessageContract)]
public class GetTransactionsRequest
{
[MessageHeader(Namespace = ServiceConstants.ContractNameSapceMessageHeader)]
public DateTime EndDate { get; set; }
[MessageHeader(Namespace = ServiceConstants.ContractNameSpaceMessageContract)]
public DateTime StartDate { get; set; }
[MessageHeader(Namespace = ServiceConstants.ContractNameSpaceMessageContract)]
public string TimeZoneInfo
{
get { return tzInfo.ToSerializedString(); }
set { tzInfo = System.TimeZoneInfo.FromSerializedString(value); }
}
private TimeZoneInfo tzInfo;
public TimeZoneInfo TZInfo
{
get { return tzInfo; }
internal set { tzInfo = value; }
}
}
I have the following Contract interface
[ServiceKnownType(typeof(System.TimeZoneInfo))]
[ServiceKnownType(typeof(System.TimeZoneInfo.AdjustmentRule))]
[ServiceKnownType(typeof(System.TimeZoneInfo.AdjustmentRule[]))]
[ServiceKnownType(typeof(System.TimeZoneInfo.TransitionTime))]
[ServiceKnownType(typeof(System.DayOfWeek))]
[ServiceContract(Name = "TransactionLobService", Namespace = ServiceConstants.ContractNameSpace)]
public interface ITransactionLobService
{
[OperationContract]
[WebGet(UriTemplate = "/GetTransactions")]
[FaultContract(typeof(ExpenseAutomationFault))]
GetTransactionsResponse GetTransactions(GetTransactionsRequest request);
}
I am consuming the service like so
Dim client As TransactionLobService = New TransactionLobServiceClient()
Dim getTransactionsRequest As New TransactionsLOBService.GetTransactionsRequest() With {
.TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time").ToSerializedString(),
.StartDate = Convert.ToDateTime("2017-03-27 00:00:00"),
.EndDate = DateTime.Now
}
Dim response = client.GetTransactions(getTransactionsRequest)
I am still getting the following error:
System.InvalidOperationException: There was an error reflecting type 'GetTransactionsRequest'. ---> System.InvalidOperationException: Cannot serialize member 'GetTransactionsRequest.TZInfo' of type 'System.TimeZoneInfo', see inner exception for more details. ---> System.InvalidOperationException: System.TimeZoneInfo cannot be serialized because it does not have a parameterless constructor.

JSON.NET: Unknown members handling on deserialization

I'm using JSON for data interchange. And I'm using JSON.NET framework.
I have the class:
public class CarEntity
{
public string Model { get; set; }
public int Year { get; set; }
public int Price { get; set; }
}
And I have following code:
public void Test()
{
var jsonString =
#"{
""Model"": ""Dodge Caliber"",
""Year"": 2011,
""Price"": 15000,
""Mileage"": 35000
}";
var parsed = (CarEntity)JsonConvert.DeserializeObject(jsonString, typeof(CarEntity));
}
Since there are no "Mileage" field in CarEntity class I need log warning about it:
Unknown field: Mileage=35000
Is there some way to do it?
It is little tricky but you can. Change your code to:
var parsed = (CarEntity)JsonConvert.DeserializeObject(jsonString, typeof(CarEntity), new JsonSerializerSettings()
{
MissingMemberHandling = MissingMemberHandling.Error,
Error = ErrorHandler
});
And add:
private static void ErrorHandler(object x, ErrorEventArgs error)
{
Console.WriteLine(error.ErrorContext.Error);
error.ErrorContext.Handled = true;
}
You should probably do more with the last line, because now every error will not throw an exception.
UPDATE
Decompiled code form invoking exception in Json.NET:
if (this.TraceWriter != null && this.TraceWriter.LevelFilter >= TraceLevel.Verbose)
this.TraceWriter.Trace(TraceLevel.Verbose, JsonPosition.FormatMessage(reader as IJsonLineInfo, reader.Path, StringUtils.FormatWith("Could not find member '{0}' on {1}", (IFormatProvider) CultureInfo.InvariantCulture, (object) propertyName, (object) contract.UnderlyingType)), (Exception) null);
if (this.Serializer.MissingMemberHandling == MissingMemberHandling.Error)
throw JsonSerializationException.Create(reader, StringUtils.FormatWith("Could not find member '{0}' on object of type '{1}'", (IFormatProvider) CultureInfo.InvariantCulture, (object) propertyName, (object) contract.UnderlyingType.Name));
reader.Skip();

DataContractJsonSerializer Date Serialization

Is there a way to change how the DataContractJsonSerializer serializes dates?
Currently, it'll convert a date to something like:
{
"date": "/Date(1260597600000-0600)/"
}
I want to convert it into human readable date format.
I am building a RestApi using openrasta framework. Can i write OperationInterceptors which will at some stage before serialization/deserialization convert JSON datetime format to something which is human readable?Or is there any other way to do it?
Use DataContractJsonSerializer constructor to pass your serialization settings:
var s = new DataContractJsonSerializer(
typeof(YourTypeToSerialize),
new DataContractJsonSerializerSettings
{
DateTimeFormat = new DateTimeFormat("yyyy-MM-dd'T'HH:mm:ss")
}
);
Finally i have handled this issue as below(c#)
[DataMember]
public string Date { get; set; }
[IgnoreDataMember]
public DateTime? DateForInternalUse { get; set; }
[OnSerializing]
public void OnSerializing(StreamingContext context)
{
Date = (DateForInternalUse != null) ? ((DateTime)DateForInternalUse).ToString(DateTimeFormatForSerialization) : null;
}
[OnDeserialized]
public void OnDeserialized(StreamingContext context)
{
try
{
DateForInternalUse = !String.IsNullOrEmpty(Date) ? DateTime.ParseExact(Date, DateTimeFormats, null, DateTimeStyles.None) : (DateTime?)null;
}
catch (FormatException)
{
DateForInternalUse = null;
}
}
In this case we can specify the formats which we want to support which i have kept inside web.config
<add key="DateTimePattern" value="yyyy-MM-dd,yyyy-MM-dd hh:mm:ss zzz,yyyy-MM-dd hh:mm:ss" />
Let me know for further clarifications.

Categories

Resources