如何传递date时间参数?

如何将UTCdate传递给Web API?

通过2010年1月1日工作正常,但是当我通过UTCdate,如2014-12-31T22:00:00.000Z (与时间组件),我得到一个HTTP 404响应。 所以

 http://domain/api/controller/action/2012-12-31T22:00:00.000Z 

产生404错误响应,而

 http://domain/api/controller/action/2012-12-31 

工作正常。

如何将UTCdate传递给Web API – 或者至less指定date时间?

我感觉到你的痛苦……又一个date时间格式…正是你需要的!

使用Web Api 2,您可以使用路由属性来指定参数。

所以对于你的类和你的方法的属性,你可以使用这种utc格式编码一个REST URL(显然它的ISO8601,大概是使用了startDate.toISOString())

 [Route(@"daterange/{startDate:regex(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$)}/{endDate:regex(^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$)}")] [HttpGet] public IEnumerable<MyRecordType> GetByDateRange(DateTime startDate, DateTime endDate) 

….但是,虽然这与一个date(startDate)工作,由于某种原因,它不工作,当endDate是在这种格式…debugging了几个小时,只有线索是exception说,它不像冒号“:”(偶虽然web.config设置为:

 <system.web> <compilation debug="true" targetFramework="4.5.1" /> <httpRuntime targetFramework="4.5.1" requestPathInvalidCharacters="" /> </system.web> 

因此,让我们制作另一种date格式(从ISOdate格式的polyfill中获取)并将其添加到Javascriptdate(为简洁起见,只能转换成分钟):

 if (!Date.prototype.toUTCDateTimeDigits) { (function () { function pad(number) { if (number < 10) { return '0' + number; } return number; } Date.prototype.toUTCDateTimeDigits = function () { return this.getUTCFullYear() + pad(this.getUTCMonth() + 1) + pad(this.getUTCDate()) + 'T' + pad(this.getUTCHours()) + pad(this.getUTCMinutes()) + 'Z'; }; }()); } 

然后,当您将date发送到Web API 2方法时,可以将它们从string转换为date:

 [RoutePrefix("api/myrecordtype")] public class MyRecordTypeController : ApiController { [Route(@"daterange/{startDateString}/{endDateString}")] [HttpGet] public IEnumerable<MyRecordType> GetByDateRange([FromUri]string startDateString, [FromUri]string endDateString) { var startDate = BuildDateTimeFromYAFormat(startDateString); var endDate = BuildDateTimeFromYAFormat(endDateString); ... } /// <summary> /// Convert a UTC Date String of format yyyyMMddThhmmZ into a Local Date /// </summary> /// <param name="dateString"></param> /// <returns></returns> private DateTime BuildDateTimeFromYAFormat(string dateString) { Regex r = new Regex(@"^\d{4}\d{2}\d{2}T\d{2}\d{2}Z$"); if (!r.IsMatch(dateString)) { throw new FormatException( string.Format("{0} is not the correct format. Should be yyyyMMddThhmmZ", dateString)); } DateTime dt = DateTime.ParseExact(dateString, "yyyyMMddThhmmZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal); return dt; } 

所以url会

 http://domain/api/myrecordtype/daterange/20140302T0003Z/20140302T1603Z 

Hanselman在这里提供一些相关信息:

http://www.hanselman.com/blog/OnTheNightmareThatIsJSONDatesPlusJSONNETAndASPNETWebAPI.aspx

问题是双重的:

1 . 在路线

默认情况下,IIS将所有的URI都以点作为静态资源,尝试将其返回并完全跳过进一步处理(通过Web API)。 这在system.webServer.handlers部分的Web.config中configuration:默认处理程序处理path="*." 。 你不会在这个path属性中find很多关于这个奇怪语法的文档(正则expression式会更有意义),但是这显然意味着什么是“不包含任何点的东西”(以及下面第二点的任何字符)。 因此名为ExtensionlessUrlHandler-Integrated-4.0的“Extensionless”。

我认为按照“正确性”的顺序,可能有多种解决scheme:

  • 为必须允许点的路由添加一个新的处理程序。 一定要在默认之前添加它。 要做到这一点,请确保先删除默认处理程序,然后将其添加回去。
  • 更改path="*." 属性为path="*" 。 它会抓住一切。 请注意,从那时起,您的web api将不再将带有点的来电解释为静态资源! 如果你在你的web api上托pipe静态资源,这是不build议的!
  • 将以下内容添加到Web.config中,以无条件处理所有请求:在<system.webserver><modules runAllManagedModulesForAllRequests="true">

2.在路线上

在你改变了上面的内容之后,默认情况下会出现以下错误:

从客户端(:)中检测到有潜在危险的Request.Path值。

您可以更改Web.config中预定义的不允许/无效字符。 在<system.web> ,添加以下内容: <httpRuntime requestPathInvalidCharacters="&lt;,&gt;,%,&amp;,*,\,?" /> <httpRuntime requestPathInvalidCharacters="&lt;,&gt;,%,&amp;,*,\,?" /> 。 我从无效字符的标准列表中删除了:

更简单/更安全的解决scheme

虽然不是您的问题的答案,但更安全和更简单的解决scheme将是更改请求,以便所有这些不是必需的:

  1. 将date作为查询stringparameter passing,如?date=2012-12-31T22:00:00.000Z
  2. 从每个请求中剥离.000 。 你仍然需要允许: (cfr第二点)。

这是可能的解决scheme的解决scheme和模型。 在客户端使用Moment.js格式化date,转换为unix时间。

  $scope.startDate.unix() 

设置你的路由参数很长。

 [Route("{startDate:long?}")] public async Task<object[]> Get(long? startDate) { DateTime? sDate = new DateTime(); if (startDate != null) { sDate = new DateTime().FromUnixTime(startDate.Value); } else { sDate = null; } ... your code here! } 

为Unix时间创build一个扩展方法。 Unix DateTime方法

在您的产品Web API控制器中:

 [RoutePrefix("api/product")] public class ProductController : ApiController { private readonly IProductRepository _repository; public ProductController(IProductRepository repository) { this._repository = repository; } [HttpGet, Route("orders")] public async Task<IHttpActionResult> GetProductPeriodOrders(string productCode, DateTime dateStart, DateTime dateEnd) { try { IList<Order> orders = await _repository.GetPeriodOrdersAsync(productCode, dateStart.ToUniversalTime(), dateEnd.ToUniversalTime()); return Ok(orders); } catch(Exception ex) { return NotFound(); } } } 

在Fiddler – Composer中testingGetProductPeriodOrders方法:

 http://localhost:46017/api/product/orders?productCode=100&dateStart=2016-12-01T00:00:00&dateEnd=2016-12-31T23:59:59 

date时间格式:

 yyyy-MM-ddTHH:mm:ss 

javascript传递参数使用了moment.js

 const dateStart = moment(startDate).format('YYYY-MM-DDTHH:mm:ss'); const dateEnd = moment(endDate).format('YYYY-MM-DDTHH:mm:ss'); 

事实上,将参数明确地指定为?date ='fulldatetime'就像魅力一样工作。 所以现在这将是一个解决scheme:不要使用逗号,而是使用旧的GET方法。

它曾经是一个痛苦的任务,但现在我们可以使用toUTCString():

例:

 [HttpPost] public ActionResult Query(DateTime Start, DateTime End) 

把下面的Ajax post请求

 data: { Start: new Date().toUTCString(), End: new Date().toUTCString() },