在一个项目中用到了SignalR,发现在DateTime的Json序列化和反序列化的时候,它的格式中的时区是未指定的,DateTimeKind.Unspecified
如果不做任何处理,SignalR所序列化一个日期2018-11-27T14:04:00+08:00(北京时间)的结果是这样的:
"2018-11-27T14:04:00"
我们想要在客户端浏览器中自动转换为浏览器端的本地时间,那么就该字符串直接调用 new Date(str) ,如果服务器时区与客户端时区不一致,那么时间就会有偏差。
例如:通过SignalR服务端序列化的字符串为 "2018-11-27T14:04:00" ,谷歌浏览器的时区为 GMT+1100
var date=new Date("2018-11-27T14:04:00");
console.info('date',date); //date Tue Nov 27 2018 14:04:00 GMT+1100 (澳大利亚东部夏令时间)
可以看到,此处时间和服务器的原时间(北京时间)是不一致的。
而且,在浏览器中修改时间之后,提交的数据的时间也是 GMT+1100 时区的。
因此,为了在前端、程序端、以及数据库中的日期统一,需要在SignalR的序列化和反序列化指定日期时间的格式化。
好在SignalR的内部序列化方法采用的是Json.Net ,正好在项目中使用的也是Json.Net。
经过研究,发现只需要在项目中注册序列化器就能实现:
public class WebHubJsonSerializer : Microsoft.AspNet.SignalR.Json.JsonNetSerializer
{
public WebHubJsonSerializer()
: base(new JsonSerializerSettings()
{
PreserveReferencesHandling = PreserveReferencesHandling.None,
TypeNameHandling = TypeNameHandling.None,
DateTimeZoneHandling = DateTimeZoneHandling.Local //重点,默认是Unspecified
})
{
}
}
GlobalHost.DependencyResolver.Register(typeof(Microsoft.AspNet.SignalR.Json.IJsonSerializer), () => new WebHubJsonSerializer());
方法GlobalHost.DependencyResolver.Register,没有查询到这个方法的详细解释,但是从结果上来看,这个方法在SinglR组件中,将默认的序列化器JsonNetSerializer替换成了 WebHubJsonSerializer 。
这样,在浏览器端得到的结果,就自动携带了时区信息:
"2018-11-27T14:04:00+0800"
在浏览器提交数据的时候,虽然时区是 GMT+1100的,但是其在反序列化的时候,也会自动将此时区的时间转换为服务器的时区,这样就实现了自动转换。