我遇到了一个我无法弄清楚的问题。
我尝试在服务器端使用UTC DateTime处理ALWAYS。
我有一个AspNetCore Mvc应用程序,其端点接受可能包含DateTimes的查询。我希望Mvc了解这些日期已经是UTC,而不是“再次”转换它们。
我的系统位于西班牙,(UTC +2)
如果我向我的localhost服务器发送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.Z变换为两小时后:2018-06-30 20:00:00
我试图告诉Mvc使用UTC json序列化器/解串器,但没有任何改变:
services
.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
});
有没有办法在http GET请求中发送查询参数作为UTC日期时间的表示?我理解ISO 8601中的日期,如果它有后缀Z,则表示“零偏移”,应该将其解释为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);
}
答案 0 :(得分:1)
感谢another question in StackOverflow我发现发生这种情况的原因是因为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"));
}
并以ISO 8601格式返回日期,如下所示:2018-06-15T20:00:00.0000000+02:00
它将查询参数反序列化,就像它是本地时间日期一样,它应用UTC + 2(因为该应用程序位于西班牙)。
我需要一种方法告诉AspNet Core Mvc反序列化程序,以了解看起来像日期的查询参数应该被视为UTC日期,而不是在反序列化时修改它。
答案是创建自定义模型绑定器并将其应用于该端点或全局。
我添加了good implementation并在添加了模型绑定提供程序和模型绑定器之后
我的端点现在返回?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
根据需要
答案 1 :(得分:0)
在查询中使用UTC日期时间时,即使使用ASP.NET-Core 3.1,此问题仍然存在。例如使用[FromQuery]
。
在此github-issue中,还提供了一个运行良好的模型绑定器。
基本上,您可以复制并插入它并进行注册
仅适用于Web-API控制器:
services.AddController(options => options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());
用于成熟的MVC管道
services.AddMvc(options => options.ModelBinderProviders.Insert(0, new DateTimeModelBinderProvider());