Correct way to use PersianCalendar as Table column in entity framework
I have an ASP.NET Web API project in which i'm trying to store my date using Persian calendar. Here is my POCO class.
public class Person
{
PersianCalendar p = new PersianCalendar();
public Person()
{
}
public Person(string firstName, string lastName, PersianCalendar birthDate)
{
FirstName = firstName;
LastName = lastName;
DateOfBirth = birthDate;
}
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public PersianCalendar DateOfBirth { get; set; }
}
I created a POST method for my API.
public HttpResponseMessage Post([FromBody] Person _p)
{
try
{
db.Persons.Add(_p);
db.SaveChanges();
var msg = Request.CreateResponse(HttpStatusCode.Created,
_p);
msg.Headers.Location = new Uri(Request.RequestUri + _p.PersonId.ToString());
return msg;
}
catch(Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
}
}
and i'm send my POST request using Fiddler.
but in the Chrome Dev Tools, break point birthDate of my Person class is set to null. Can anyone help me with what is wrong? How can i send my date in persian format??
The DateOfBirth
in your model POCO should not be of type PersianCalendar
. A calendar is used to manipulate DateTime
objects, not as a container of DateTime
objects.
Your model should store the date of birth as a normal DateTime
, then you can use a PersianCalendar
to manipulate it. The easy (but a bit ugly) way to do this is to have a DateTime
field and a separate public string
property for getting and setting the date as formatted by the Persian calendar:
public class Person
{
PersianCalendar p = new PersianCalendar();
public Person()
{
}
public Person(string firstName, string lastName, DateTime birthDate)
{
FirstName = firstName;
LastName = lastName;
DateOfBirth = birthDate;
}
public Person(string firstName, string lastName, string birthDateString)
{
FirstName = firstName;
LastName = lastName;
DateOfBirthString = birthDateString;
}
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth;
public string DateOfBirthString
{
get
{
return string.Format("{0}/{1}/{2}", p.GetYear(DateOfBirth), p.GetMonth(DateOfBirth), p.GetDayOfMonth(DateOfBirth));
}
set
{
var parts = value.Split('/');
DateOfBirth = p.ToDateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), 0, 0, 0, 0);
}
}
}
Keep in mind that a DateTime
represents a general specific moment in time. It does not have any uniquely correct string representation. But if you use something like what I have above, then you are kind of deciding that for your application the only correct string representation is a Persian date, formatted as yyyy/MM/dd
.
EDIT : You can also create a custom JSON JsonConverter
and use that in your model. Your POCO model could then look like this:
public class Person
{
public Person() { }
public Person(string firstName, string lastName, DateTime birthDate)
{
FirstName = firstName;
LastName = lastName;
DateOfBirth = birthDate;
}
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[JsonConverter(typeof(PersianDateConverter))]
public DateTime DateOfBirth;
}
And the PersianDateConverter
class looks like this:
public class PersianDateConverter : JsonConverter
{
PersianCalendar pc = new PersianCalendar();
public PersianDateConverter()
{
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string persianDateString = reader.Value as string;
if (persianDateString == null)
throw new ArgumentException("Error in PersionDateConverter.ReadJson: Got null string");
var parts = persianDateString.Split('/');
return pc.ToDateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), 0, 0, 0, 0);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
DateTime d = (DateTime)value;
string output = string.Format("{0}/{1}/{2}", pc.GetYear(d), pc.GetMonth(d), pc.GetDayOfMonth(d));
writer.WriteValue(output);
}
public override bool CanConvert(Type objectType)
{
if (objectType.Name == "DateTime")
return true;
return false;
}
}
Note : This PersianDateConverter
is not well tested for edge cases. Seems to work ok as long as the data it is manipulating is valid though.