在WebAPI 2中控制DateTime参数格式

Zoi*_*nks 17 c# format datetime asp.net-web-api

所以我有一个用C#编写的WebAPI 2控制器,它带有一个DateTime类型的查询参数.这是一个API,它根据日期过滤器返回数据存储中的所有值.比如,让我们说:

public MyThing GetThing([FromUri]DateTime startTime)
{
 // filter and return some results
}
Run Code Online (Sandbox Code Playgroud)

我遇到了两个问题:

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

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

  1. 通过FromUri查询参数传递的日期时间被正确理解为ISO8601,包括适当的时区偏移
  2. UrlHelper.Link()以通用可执行的静态类型方式在输出URI字符串中生成符合ISO8601的DateTimes.

WebAPI 2提供了很好的格式化JSON的钩子,我确实使用了它,因此只需在JSON体中返回一个DateTime,就可以根据需要使用ISO8601格式进行格式化,并且在[FromBody] JSON体中正确理解它.我找不到绕URI处理的方法,我真的很想!

小智 6

您可以使用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;
    }
Run Code Online (Sandbox Code Playgroud)

以这种方式,您可以将其设置为DateTime的默认模型.

ModelBinders.Binders.Add(typeof(DateTime), new UtcDateTimeModelBinder());
Run Code Online (Sandbox Code Playgroud)


asi*_*dis 5

Why not using DateTimeOffset instead of DateTime if you want to keep UTC offset? Here are some code working with JSON serialization:

Api Controller:

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

Razor View sample code (assuming you have the default api route created in a MVC + Web API Visual studio template )

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

Rendered as:

<a href="/api/values?dt=06%2F26%2F2018%2009%3A37%3A24%20%2B00%3A00">Utc Now</a>
Run Code Online (Sandbox Code Playgroud)

And you can call your API with datetime offset:

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"}
Run Code Online (Sandbox Code Playgroud)


小智 1

1.

您应该检查参数“startTime”的时区(应该是您的服务器/计算机的时区)。

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

2.

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