控制WebAPI中DateTime参数的格式

本文关键字:格式 参数 DateTime WebAPI 控制 | 更新日期: 2023-09-27 18:08:06

所以我有一个用c#编写的WebAPI 2控制器,它在其他事情中接受DateTime类型的查询参数。这是一个API,它根据日期过滤器从数据存储返回所有值。比如,我们说:

public MyThing GetThing([FromUri]DateTime startTime)
{
 // filter and return some results
}

我遇到了两个问题:

  1. 由于某些原因,尽管传入了ISO 8601 UTC格式(带Z)日期,WebAPI将其反序列化为本地DateTime而不是UTC。这显然是不可取的。我不确定如何修改管道,使其正确理解UTC-0日期时间。
  2. 我返回一个链接回到资源作为响应体的一部分,其中我使用UrlHelper对象(从父ApiController抽象类获得)link()方法来生成一个href。我正在传递我想要添加到路由的查询参数集合。无论出于何种原因,传递DateTime将其格式化为非iso8601格式。我找不到被控制的地方。我不想显式地使用ToString(),因为这不是通用的。

简而言之,我想弄清楚如何确保

  1. 通过FromUri查询参数传入的日期时间被正确理解为ISO8601,包括适当的时区偏移
  2. UrlHelper.Link()以通用强制的静态类型方式在输出URI字符串中生成符合iso8601的日期时间。
WebAPI 2确实为格式化JSON提供了很棒的钩子,我确实使用了它,所以简单地返回JSON主体中的DateTime,使用ISO8601格式将其格式化,并且在[FromBody] JSON主体中也可以正确理解。虽然我找不到在URI处理周围拉字符串的方法,但我真的很想!

控制WebAPI中DateTime参数的格式

您可以使用modelbinder将传入的数据转换为您的模型。

GetThings([ModelBinder(typeof(UtcDateTimeModelBinder)), FromUri] DateTime dt){//do somthing}

public class UtcDateTimeModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
        {
            throw new ArgumentNullException(nameof(bindingContext));
        }
        if (bindingContext.ModelMetadata.ModelType == typeof(DateTime))
        {
            var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
            var str = valueProviderResult.AttemptedValue;
            return DateTime.Parse(str).ToUniversalTime();
        }
        return null;
    }

这样你就可以将它设置为DateTime的默认建模器。

ModelBinders.Binders.Add(typeof(DateTime), new UtcDateTimeModelBinder());

如果你想保持UTC偏移量,为什么不使用DateTimeOffset而不是DateTime ?下面是一些使用JSON序列化的代码:

Api控制器:

public class ValuesController : ApiController
{
    public object Get(DateTimeOffset dt)
    {
        return new {
            Input = dt,
            Local = dt.LocalDateTime,
            Utc = dt.UtcDateTime
        };
    }
}

Razor View示例代码(假设你在MVC + Web api Visual studio模板中创建了默认的api路由)

<a href="@Url.RouteUrl("DefaultApi",new {httproute = "",controller = "values",dt = DateTimeOffset.UtcNow})">Utc Now</a>

呈现为:

<a href="/api/values?dt=06%2F26%2F2018%2009%3A37%3A24%20%2B00%3A00">Utc Now</a>

你可以用datetime offset来调用API:

2018-06-26T08:25:48Z: http://localhost:1353/api/values?dt=2018-06-26T08:25:48Z
{"Input":"2018-06-26T08:25:48+00:00","Local":"2018-06-26T10:25:48+02:00","Utc":"2018-06-26T08:25:48Z"}
2018-06-26T08:25:48+01:00: http://localhost:1353/api/values?dt=2018-06-26T08%3A25%3A48%2B01%3A00 (note that : and + must be url encoded)
{"Input":"2018-06-26T08:25:48+01:00","Local":"2018-06-26T09:25:48+02:00","Utc":"2018-06-26T07:25:48Z"}

发送的查询字符串参数值是UTC时间。所以,同样的会被翻译成基于本地时钟的时间你调用ToUniversalTime(),它被转换回UTC

那么,问题到底是什么呢?如果问题是为什么会这样如果作为查询字符串发送,而不是在请求中发布时发生,这个问题的答案是ASP。. NET Web API绑定URI路径,查询字符串等使用模型绑定和主体使用参数绑定。对于后者,它使用媒体格式化器。如果你发送JSON,使用JSON媒体格式化器,它是基于JSON.NET的。

因为你指定了DateTimeZoneHandling。它使用Utc设置,你得到你想要的日期时间类型。顺便说一句,如果你改变此设置为DateTimeZoneHandling。本地的,然后你会看到相同的行为作为模型绑定。

意思是为了得到你想要的格式,你所需要做的就是调用ToUniversalTime()方法。

1.

你应该检查你的参数'startTime'的时区(它应该是你的服务器/计算机的时区)。

Web API提供的DateTime是正确的,它只是取决于你的时区。

2。

创建一个Json DateTime序列化器以生成ISO8601格式的日期