实体框架 – 我们如何使用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 – 这是一个很好的SOA架构吗?
- asp.net中的SqlDependency
- 以编程方式从webforms页面调用asp.net mvc控制器操作
- asp.net-mvc – 如何将值传递给MVC3母版页(_layout)?
- IoC在ASP.NET Web API中的应用
- asp.net-mvc – 如何在运行时之前编译cshtml
- asp.net – 如何在网格中按日期升序?
- asp.net-mvc – 当参数为Model时,ASP.NET MVC发布文件模型绑
- 在ASP.Net中如何做一个搜索表单?
- dropdownlist事件不显示在属性窗口asp.net Visual Studio 2
- 浅谈ASP.NET Core 2.0 中间件(译)
- asp.net-mvc – 使用ModelState.Remove处理Model
- asp.net-mvc – 在ascx文件中使用Html.RenderPar
- .net – MVC,ViewModels和Validation
- asp.net – 如何禁用.NET事件日志警告?
- asp.net – 对良好的自动化Web负载测试工具的任何
- Asp.net Web API:控制器上未找到任何操作
- asp.net-mvc – 用于ASP.NET MVC 3的NuGet软件包
- .net – 类库项目中特定于语言的资源文件的问题
- asp.net-mvc – HTML.CheckBox(string)计算为两个