asp.net mvc 2 - JavaScriptSerializer no deserializa DateTime/TimeSpan correctamente
asp.net-mvc-2 (2)
Tener un problema donde DateTime / TimeSpan no parece deserializarse correctamente con JavaScriptSerializer. Cuando recupero el objeto después de deserializarlo, TimeSpan está vacío y si uso DateTime, los tiempos están fuera de control. Encontré este artículo pero realmente no me ayudó demasiado. http://www.west-wind.com/weblog/ShowPost.aspx?id=471402
¿Alguien tiene alguna idea? ¿Debería probar la biblioteca json.net?
public class JsonFilter : ActionFilterAttribute
{
public string Param { get; set; }
public Type JsonDataType { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
{
string inputContent;
using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream))
{
inputContent = sr.ReadToEnd();
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
var result = serializer.Deserialize(inputContent, JsonDataType);
filterContext.ActionParameters[Param] = result;
}
}
}
public class RosterItem
{
public RosterItem()
{
comments = new List<Form.Comment>();
}
public Boolean dirty { get; set; }
public int id { get; set; }
public int staffId { get; set; }
public String description { get; set; }
public int activityId { get; set; }
public DateTime date { get; set; }
public TimeSpan startTime { get; set; }
public TimeSpan endTime { get; set; }
public List<Form.Comment> comments { get; set; }
}
[JsonFilter(Param = "rosterItem", JsonDataType = typeof(RosterItem))]
public int SaveRosterEntry(RosterItem rosterItem)
{
RosterEntry rosterEntry = rosterEntryRepository.GetRosterEntry(rosterItem.id);
if (rosterEntry == null)
{
rosterEntry = new RosterEntry();
rosterEntryRepository.Add(rosterEntry);
}
rosterEntry.ActivityID = rosterItem.activityId;
rosterEntry.StartTime = rosterItem.startTime;
rosterEntry.EndTime = rosterItem.endTime;
rosterEntry.RosterDate = rosterItem.date;
rosterEntry.RosterEmployeeID = rosterItem.staffId;
rosterEntryRepository.Save();
return rosterEntry.RosterEntryID;
}
Esto solucionará su problema si alguna vez tiene el mismo problema.
http://blog.devarchive.net/2008/02/serializing-datetime-values-using.html
Todos los objetos DateTime deben especificarse explícitamente como UTC.
Encontré la respuesta en la siguiente publicación en GitHub:
https://github.com/NancyFx/Nancy/issues/336
Básicamente, la respuesta fue crear un nuevo TimeSpanJsonConverter
que hereda de JavaScriptConverter
y luego pasarlo a una instancia de su clase de serializador:
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer()
serializer.RegisterConverters(new[] { new TimeSpanJsonConverter() });
La clase completa de referencia es (escrita por GrumpyDev ):
public class TimeSpanJsonConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get
{
return new[] { typeof(TimeSpan) };
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
return new TimeSpan(
this.GetValue(dictionary, "days"),
this.GetValue(dictionary, "hours"),
this.GetValue(dictionary, "minutes"),
this.GetValue(dictionary, "seconds"),
this.GetValue(dictionary, "milliseconds"));
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var timeSpan = (TimeSpan)obj;
var result = new Dictionary<string, object>
{
{ "days", timeSpan.Days },
{ "hours", timeSpan.Hours },
{ "minutes", timeSpan.Minutes },
{ "seconds", timeSpan.Seconds },
{ "milliseconds", timeSpan.Milliseconds }
};
return result;
}
private int GetValue(IDictionary<string, object> dictionary, string key)
{
const int DefaultValue = 0;
object value;
if (!dictionary.TryGetValue(key, out value))
{
return DefaultValue;
}
if (value is int)
{
return (int)value;
}
var valueString = value as string;
if (valueString == null)
{
return DefaultValue;
}
int returnValue;
return !int.TryParse(valueString, out returnValue) ? DefaultValue : returnValue;
}
}