I have an xml where the TimeStamp is not set. I have tried every possible combination here but on deserialization it always throws an exception with: There was an error deserializing the object of type MyType. The value '' cannot be parsed as the type 'DateTime'.
[DataMember(IsRequired = false, EmitDefaultValue = false)]
public DateTime TimeStamp = DateTime.Now;
What exactly do I need to set on this TImeStamp member so that it is optional on deserialization (=not needed to be in the xml)
EDIT: What I tried on Xaruth's suggestion:
[DataMember]
[DefaultValue(typeof(DateTime), "2014-08-25T09:31:09.2477328+02:00")]
public DateTime TimeStamp { get; set; }
public bool ShouldSerializeTimeStamp()
{
return TimeStamp != null;
}
public void ResetTimeStamp()
{
TimeStamp = DateTime.Now;
}
You can use methods SouldSerialize and Reset, wich can be define for any properties.
For a property called TimeStamp, you can write methods SouldSerializeTimeStamp and ResetTimeStamp
According to MSDN, ResetTimeStamp will give you a default value for TimeStamp and SouldSerializeTimeStamp will be used to serialize or not TimeStamp.
Related
We have a API service that we are updating and we converted some date objects from strings to DateTime objects. In the old code we tested the string if it would parse to a data time or not. If it was a bad formatted string, it would assign DateTime.Min and continue on. Now customers are sending in bad dates and it blows up since the serialization happens outside our code (MVC Controller). I am trying to find some way that when serializing a DateTime object, if it can not parse it, it just returns DateTime.Min instead of blowing up the call.
Here is the response from the API Call.
{
"date": [
"Could not convert string to DateTime: Invalid Date. Path 'date', line 3, position 24."
]
}
===== UPDATE =====
I finally found somewhere that recommended a custom JsonConverter. I finally got something that works, but there is little out there so if there is something I could do better I am all ears.
Custom Converter
public class DateConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
try
{
return DateTime.Parse(reader.Value.ToString());
}
catch (Exception ex)
{
return DateTime.MinValue;
}
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTime);
}
}
DTO Class
public class Request
{
[JsonConverter(typeof(SafeDateConverter))]
public DateTime Date { get; set; }
}
Another approach introduce another property on deserialized class of type DateTime? and leave original string property as it is.
public class Request
{
public string Date { get; set; }
private DateTime? _parsedDate;
[JsonIgnore]
public DateTime? ParsedDate
{
get { return _parsedDate; }
set
{
if (DateTime.TryParse(value, out DateTime parsed)
{
_parsedDate = parsed;
return;
}
_parsed = null;
}
}
}
But having custom serializer looks better, because you need change nothing in the code which already uses deserialized object.
Suggestion:
Do not use try ... catch for serializing bad formatted dates, there is DateTime.TryParse method which will do this without throwing exceptions.
And if it is not late, you can use Nullable<DateTime> instead of having DateTime.Min as "not existing" value.
UPDATE
Found the issue -- was inheriting from wrong class, needed to be JsonConverter.
I have a class that has a Location property of type System.Data.Entity.Spatial.DbGeography. The default Json.NET serializer puts out JSON text like this:
...
"PlaceType": 0,
"Location": {
"Geography": {
"CoordinateSystemId": 4326,
"WellKnownText": "POINT (-88.00000 44.00000)"
}
},
"AddedDT": null,
...
I want it to put out text like this:
...
"PlaceType": 0,
"Location": [-88.00000,44.00000],
"AddedDT": null,
...
...so it seems to me what I should do would be to override whatever converter is currently being used on the DbGeography type.
The examples I've seen so far that use CustomCreationConverters and ContractResolvers seem to address how you'd replace the serializer for the main class being serialized, not for a type that's only a property of that class. The examples that involve annotating the class that's being overridden don't work for me because I don't define DbGeography in my code and it's effectively a sealed class because it has no constructor and can only be instantiated by internal factory methods.
Is there a way to apply a JsonConverter to a type fluently? If so, what would the converter look like? Do I just override the WriteJson() method?
You can add a custom serializer to a single attribute like this:
public class Comment
{
public string Author { get; set; }
[JsonConverter(typeof(NiceDateConverter))]
public DateTime Date { get; set; }
public string Text { get; set; }
}
public class NiceDateConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var date = (DateTime) value;
var niceLookingDate = date.ToString("MMMM dd, yyyy 'at' H:mm tt");
writer.WriteValue(niceLookingDate);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
}
public override bool CanRead
{
get { return false; }
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTime);
}
}
Then, when you serialize your object with JsonConvert.SerializeObject(), the custom serializer will be used for the Date property.
Turns out I just needed to inherit from JsonConverter instead of CustomCreationConverter, and everything else I was trying to change was OK all along.
I'm still not sure if there's a way to apply the JsonConverter fluently, but there is another way to apply the JsonConverter without referencing Json.NET in your domain/core project or marking up your domain classes with references to a peripheral library:
var jsonSerializer = new JsonSerializer();
jsonSerializer.Converters.Add(new DbGeographyConverter());
jsonSerializer.Serialize(jsonWriter, place);
Use the JsonConverterAttribute on the property and define a custom converter-
for example, we have a property that comes in as a unix value (long int) and we serialize it to a .Net DateTime:
[JsonConverter(typeof(UnixTimeJsonConverter))]
public DateTime Requested { get; set; }
I am looking to place attributes on my WCF data contract members to validate string length and possibly use regex for more granular parameter validation.
I can the [Range] attribute for numeric and DateTime values and was wondering if any of you have found any other WCF Data Member attributes I can use for data validation. I have found a bevvy of attributes for Silverlight but not for WCF.
Add System.ComponentModel.DataAnnotations reference to your project.
The reference provides some DataAnnotations which are:
RequiredAttribute, RangeAttribute, StringLengthAttribute, RegularExpressionAttribute
you can in your datacontract like below.
[DataMember]
[StringLength(100, MinimumLength= 10, ErrorMessage="String length should be between 10 and 100." )]
[StringLength(50)] // Another way... String max length 50
public string FirstName { get; set; }
[DataMember]
[Range(2, 100)]
public int Age { get; set; }
[DataMember]
[Required]
[RegularExpression(#"\b[A-Z0-9._%-]+#[A-Z0-9.-]+\.[A-Z]{2,4}\b", ErrorMessage = "Invalid Mail id")]
public string Email { get; set; }
Hope this helps.
Manually Validating Values: You can manually apply the validation test by using the Validator class. You can call the ValidateProperty method on the set accessor of a property to check the value against the validation attributes for the property. You must also set both ValidatesOnExceptions and NotifyOnValidationError properties to true when data binding to receive validation exceptions from validation attributes.
var unsafeContact = Request["contactJSON"];
try
{
var serializer = new DataContractJsonSerializer(typeof(Contact));
var stream = new MemoryStream(Encoding.UTF8.GetBytes(unsafeContact));
Contact = serializer.ReadObject(stream) as Contact;
stream.Close();
}
catch (Exception)
{
// invalid contact
}
Contact class:
[DataContract]
public sealed class Contact
{
/// <summary>
/// Contact Full Name
/// </summary>
/// <example>John Doe</example>
[DataMember(Name = "name", IsRequired = true)]
[StringLength(100, MinimumLength = 1, ErrorMessage = #"Name length should be between 1 and 100.")]
public string Name {
get
{
return HttpUtility.HtmlEncode(_name);
}
internal set
{
Validator.ValidateProperty(value, new ValidationContext(this, null, null) { MemberName = "Name" });
_name = value;
}
}
private string _name;
// ...
}
Try to look look for WCF Data Annotations. WCFDataAnnotations allows you to automatically validate WCF service operation arguments using System.ComponentModel.DataAnnotations attributes.
http://wcfdataannotations.codeplex.com/
[DataMember]
public int? NumberOfPages; //////////// Is this supported????
[DataMember]
public bool? Color; //////////// Is this supported????
[DataMember]
public int? BulkQuantity;
[DataMember]
Yes, of course!
You should have no trouble whatsoever to create nullable data members, they'll be handled in the resulting WSDL/XSD as "xs:nillable=true" members. No problem at all.
Yes, please see Types Supported by the Data Contract Serializer:
Nullable types are fully supported by the data contract serializer.
#Kahoon and Batwad:
We solved this problem by using the nullable<> or ? type in two steps:
In the class containing the generic field, define the field as follows:
nullable<GenType> MyField {get; set;}
In the data contract that uses this baseclass, you can define which elements are known to the serializer/deserializer using some annotation-like tags. Here, we defined for example:
[Serializable]
[DataContract]
[KnownType(typeof(BaseClass<nullable<DateTime>>))]
Instead of BaseClass<nullable<DateTime>> you can use BaseClass<DateTime?>, I think.
After this, the serialization of generic null values worked for us.
In my case It looks like that the Nullable Integer passed in is treated as Empty String and NOT Null Value
So here is how I handle the nullable in the code
[XmlIgnore]
public int? NumberOfPagesCount{ get; set; }
[XmlElement("NumberOfPages")]
public string NumberOfPagesText
{
get { return this.NumberOfPagesCount.HasValue ? this.NumberOfPagesCount.Value.ToString("F2") : string.Empty; }
set
{
if (!string.IsNullOrEmpty(value))
{
this.NumberOfPagesCount= Convert.ToInt32(value);
}
else
{
this.NumberOfPagesCount= null;
}
}
}
I have a [DataContract] called ReportRequest with a
NOT NULL column 'SubmittedAt'. So my DataContract looks something like:
[DataContract]
public class ReportRequest
{
Int32 templateId;
DateTime submittedAt = DateTime.Now;
[DataMember]
public virtual Int32? Id
{
get;
set;
}
public virtual DateTime SubmittedAt
{
get {
return submittedAt;
}
set
{
submittedAt = value;
}
}
}
Because, I have taken a private variable submittedAt and is initialised with DateTime.Now,
shouldn't the SubmittedAt property have the same value??
But when i am calling NHibernate
session.Save(objReportRequest);
I am getting the error:
SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
Any thoughts why I am getting this error?
As a workaround for now I have changed getter for SubmittedAt property as:
get {
if (submittedAt == DateTime.MinValue)
return DateTime.Now;
else
return submittedAt;
}
SQL Server minimum DateTime value is bigger than DateTime.Min value. So you cannot save minimum value to database.
As Marek Tihkan already said: SqlServer can not store the DateTime.MinValue, it is outside of the value range of SqlServer's DateTime data type.
The best advise is to use nullable types anyway:
[DataContract]
public class ReportRequest
{
DateTime? submittedAt = null;
public virtual DateTime? SubmittedAt
{
get {
return submittedAt;
}
set
{
submittedAt = value;
}
}
}
By SubmittedAt.HasValue you know if it is actually set to something reasonable. You shouldn't depend on some "magic values" to decide if a value is initialized or not.
It's because DateTime.MinValue doesn't have the same meaning as the minimum value you could store in a SQL Server datetime column. In SQL server datetime column the minimum date you could store is the one you get in your exception stack. It is SqlDateTime.MinValue