AspNet Core 中 UTC 格式的 Http 查询参数

Http Query Parameters in UTC in AspNet Core

我遇到了一个我无法解决的问题。

我总是尝试在服务器端处理 UTC 日期时间。

我有一个 AspNetCore Mvc 应用程序,其端点接受可能包含日期时间的查询。我想让 Mvc 明白这些日期已经在 UTC 中而不是转换它们 "again".

我的系统在西班牙,(UTC +2)

如果我像这样向本地主机服务器发送 http 请求:

http://localhost:50004/api/Resources?appliesOn=2018-06-30T18:00:00.000Z

我希望将反序列化的日期时间作为 UTC 表示与以下日期相同的日期:

DateTime.SpecifyKind(new DateTime(2018, 6, 30, 18, 0, 0), DateTimeKind.Utc)

但我可以看到Mvc总是将日期2018-06-30T18:00:00.000Z转换成两小时后:2018-06-30 20:00:00

我试图告诉 Mvc 使用 UTC json serializer/deserializer 但没有任何改变:

services
  .AddMvc()
  .AddJsonOptions(options =>
  {
      options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
  });

有没有办法在已经作为 UTC 日期时间表示的 http GET 请求中发送查询参数?我理解 ISO 8601 中的日期,如果它有后缀 Z,则表示 "zero-offset" 应该已经被解释为 UTC 日期时间。为什么 Mvc 然后要对此进行转换并添加 2 小时的偏移量?

任何澄清将不胜感激!

PS:这是我的终点,没有什么特别的,如您所见:

[HttpGet("")]
public IActionResult GetResources()
{
    var displayUri = Request.GetDisplayUrl();
    var requestUri = new Uri(displayUri);
    var filter = _filteredRequestFactory.Create(requestUri);
    var resources = _myProjection.GetResourcers(filter);
    return Ok(resources);
}

感谢 another question in Whosebug 我发现发生这种情况的原因是因为 AspNetCore Mvc 反序列化器甚至没有在 GET http 请求中使用 Json.Net 反序列化器来反序列化查询参数。

因此提出以下要求: http://localhost:50004/api/DateTests?date=2018-06-15T18:00:00.000Z

将被我的端点捕获:

[HttpGet("")]
public IActionResult GetDate(DateTime date)
{
    return Ok(date.ToString("o"));
}

和return ISO 8601格式的日期如下:2018-06-15T20:00:00.0000000+02:00

它将查询参数反序列化为本地时间日期,并应用 UTC + 2(因为该应用位于西班牙)。

我需要一种方法来告诉 AspNet Core Mvc 反序列化程序了解看起来像日期的查询参数应该已经被视为 UTC 日期,并且在反序列化时不要修改它。

答案是创建自定义模型活页夹并将其应用于该端点或全局。

我找到了一个 good implementation 并在添加该模型绑定器提供程序和模型绑定器之后,

我的端点现在 returns 用于 ?date=2018-06-15T18:00:00.000Z 的请求:

2018-06-15T18:00:00.0000000 作为 UTC 类型的日期时间。

如果我传递 ?date=2018-06-11T18:00:00+0100 它将作为本地时间类型被检索,结果将是: 2018-06-11T19:00:00.0000000+02:00

随心所欲

即使在 ASP.NET-Core 3.1 中使用 UTC 日期时间查询时,这个问题仍然存在。例如 [FromQuery].

在此 github-issue 中提供了一个也非常有效的模型绑定器。

基本上你可以复制并粘贴它并注册它

仅限 Web-API 控制器:

services.AddController(options => options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());

对于成熟的 MVC 管道

services.AddMvc(options => options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());