实体框架 – 我们如何使用Breeze的本地时区生存
|
我正在写这个来收集对我们的方法的意见,并希望帮助别人(和我的记忆). 脚本 >我们所有的数据库都使用没有时区信息的DateTime数据类型. 我们的问题 >没有具体的时区信息,Breeze / Web Api / Entity Framework栈似乎赞成时间是UTC而不是本地的假设,这可能是最好的,但不适合我们的应用程序. 我们的目标是确保我们的服务器端代码(和数据库)始终使用本地时区中的日期,并且所有查询返回所需的结果. 解决方法我们的解决方案第1部分:实体框架当实体框架从数据库中获取DateTime值时,将其设置为DateTimeKind.Unspecified.换句话说,本地或UTC.我们特意将日期标记为DateTimeKind.Local. 为了实现这一点,我们决定调整实体框架的生成实体类的模板.而不是我们的日期是一个简单的属性,我们引入了一个后台存储日期,并使用属性设置器将日期设置为本地,如果它是未指定的. 在模板(.tt文件)中,我们更换了… public string Property(EdmProperty edmProperty)
{
return string.Format(
CultureInfo.InvariantCulture,"{0} {1} {2} {{ {3}get; {4}set; }}",Accessibility.ForProperty(edmProperty),_typeMapper.GetTypeName(edmProperty.TypeUsage),_code.Escape(edmProperty),_code.SpaceAfter(Accessibility.ForGetter(edmProperty)),_code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
}
…与… public string Property(EdmProperty edmProperty)
{
// Customised DateTime property handler to default DateKind to local time
if (_typeMapper.GetTypeName(edmProperty.TypeUsage).Contains("DateTime")) {
return string.Format(
CultureInfo.InvariantCulture,"private {1} _{2}; {0} {1} {2} {{ {3}get {{ return _{2}; }} {4}set {{ _{2} = DateKindHelper.DefaultToLocal(value); }}}}",_code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
} else {
return string.Format(
CultureInfo.InvariantCulture,_code.SpaceAfter(Accessibility.ForSetter(edmProperty)));
}
}
这造成了一个相当丑陋的一线设置者,但它完成了工作.它使用帮助函数将日期默认为本地,如下所示: public class DateKindHelper
{
public static DateTime DefaultToLocal(DateTime date)
{
return date.Kind == DateTimeKind.Unspecified ? DateTime.SpecifyKind(date,DateTimeKind.Local) : date;
}
public static DateTime? DefaultToLocal(DateTime? date)
{
return date.HasValue && date.Value.Kind == DateTimeKind.Unspecified ? DateTime.SpecifyKind(date.Value,DateTimeKind.Local) : date;
}
}
我们的解决方案第2部分:IQueryable过滤器 下一个问题是Breeze在将where子句应用于IQueryable控制器操作时通过UTC日期.在审查了Breeze,Web API和实体框架的代码后,我们决定最好的选择是拦截对我们的控制器操作的调用,并在本地日期的QueryString中交换UTC日期. 我们选择使用我们可以应用于我们的控制器操作的自定义属性来执行此操作,例如: [UseLocalTime]
public IQueryable<Product> Products()
{
return _dc.Context.Products;
}
实现此属性的类是: using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Http.Filters;
using System.Text.RegularExpressions;
using System.Xml;
namespace TestBreeze.Controllers.api
{
public class UseLocalTimeAttribute : ActionFilterAttribute
{
Regex isoRegex = new Regex(@"((?:-?(?:[1-9][0-9]*)?[0-9]{4})-(?:1[0-2]|0[1-9])-(?:3[0-1]|0[1-9]|[1-2][0-9])T(?:2[0-3]|[0-1][0-9]):(?:[0-5][0-9]):(?:[0-5][0-9])(?:.[0-9]+)?Z)",RegexOptions.IgnoreCase);
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
// replace all ISO (UTC) dates in the query string with local dates
var uriString = HttpUtility.UrlDecode(actionContext.Request.RequestUri.OriginalString);
var matches = isoRegex.Matches(uriString);
if (matches.Count > 0)
{
foreach (Match match in matches)
{
var localTime = XmlConvert.ToDateTime(match.Value,XmlDateTimeSerializationMode.Local);
var localString = XmlConvert.ToString(localTime,XmlDateTimeSerializationMode.Local);
var encoded = HttpUtility.UrlEncode(localString);
uriString = uriString.Replace(match.Value,encoded);
}
actionContext.Request.RequestUri = new Uri(uriString);
}
base.OnActionExecuting(actionContext);
}
}
}
我们的解决方案第3部分:Json 这可能更有争议,但是我们的网络应用程序受众也完全是本地的:). 我们希望Json默认发送到客户端以包含本地时区的日期/时间.此外,我们还希望从客户端收到的Json中的任何日期转换为本地时区.为此,我们创建了一个自定义的JsonLocalDateTimeConverter并交换出了Json转换器Breeze的安装. 转换器如下所示: public class JsonLocalDateTimeConverter : IsoDateTimeConverter
{
public JsonLocalDateTimeConverter () : base()
{
// Hack is for the issue described in this post (copied from BreezeConfig.cs):
// https://stackoverflow.com/questions/11789114/internet-explorer-json-net-javascript-date-and-milliseconds-issue
DateTimeFormat = "yyyy-MM-ddTHH:mm:ss.fffK";
}
// Ensure that all dates go out over the wire in full LOCAL time format (unless date has been specifically set to DateTimeKind.Utc)
public override void WriteJson(JsonWriter writer,object value,JsonSerializer serializer)
{
if (value is DateTime)
{
// if datetime kind is unspecified then treat is as local time
DateTime dateTime = (DateTime)value;
if (dateTime.Kind == DateTimeKind.Unspecified)
{
dateTime = DateTime.SpecifyKind(dateTime,DateTimeKind.Local);
}
base.WriteJson(writer,dateTime,serializer);
}
else
{
base.WriteJson(writer,value,serializer);
}
}
// Ensure that all dates arriving over the wire get parsed into LOCAL time
public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer)
{
var result = base.ReadJson(reader,objectType,existingValue,serializer);
if (result is DateTime)
{
DateTime dateTime = (DateTime)result;
if (dateTime.Kind != DateTimeKind.Local)
{
result = dateTime.ToLocalTime();
}
}
return result;
}
}
最后,我们创建了一个CustomBreezeConfig类: public class CustomBreezeConfig : Breeze.WebApi.BreezeConfig
{
protected override JsonSerializerSettings CreateJsonSerializerSettings()
{
var baseSettings = base.CreateJsonSerializerSettings();
// swap out the standard IsoDateTimeConverter that breeze installed with our own
var timeConverter = baseSettings.Converters.OfType<IsoDateTimeConverter>().SingleOrDefault();
if (timeConverter != null)
{
baseSettings.Converters.Remove(timeConverter);
}
baseSettings.Converters.Add(new JsonLocalDateTimeConverter());
return baseSettings;
}
}
就是这样欢迎所有意见和建议. (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net – NHibernate线程安全与会话
- asp.net-mvc – 在MVC SignalR服务器和Windows服务SIgnalR客
- asp.net-mvc – 在ASP.Net MVC中定义自定义URL路由
- asp.net – 在web.config文件中设置重定向
- asp.net-mvc – ASP.NET MVC:如何从Html.ActionLink链接中
- asp.net-core – Netcore 2.1.1版本导致应用程序无法运行
- asp.net-mvc-3 – 如何模拟查询字符串
- asp.net-mvc – ASP.NET MVC – 能够处理数组的自定义模型绑
- asp.net-core – 如何根据ASP.NET Core中的解决方案配置运行
- ASP.NET的BlogEngine.Net堆栈到WordPress?
