使用ASP.NET Web API将表单yyyy-MM-dd的日期查询参数反序列化为noda time LocalDate对象

Rya*_*lor 8 c# asp.net-web-api nodatime

我正在研究使用NodaTime LocalDate来替换我们现有的BCL DateTime/DateTimeOffset类.由于我们对DateTime可论证的模糊行为的误解,我们在代码中遇到了许多与时区相关的问题.

为了充分利用NodaTime,我希望能够从YYYY-MM-DD形式的ASP.NET Web API 2 Web服务发送和接收日期.我已成功将LocalDate正确序列化为YYYY-MM-DD.但是,我无法将日期查询参数反序列化为LocalDate.LocateDate始终是1970-01-01.

这是我当前的原型代码(为清楚起见,删除了一些代码):

PeopleController.cs

[RoutePrefix("api")]
public class PeopleController : ApiController
{
    [Route("people")]
    public LocalDate GetPeopleByBirthday([FromUri]LocalDate birthday)
    {
        return birthday;
    }
}
Run Code Online (Sandbox Code Playgroud)

的Global.asax.cs

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        // Web API configuration and services
        var formatters = GlobalConfiguration.Configuration.Formatters;
        var jsonFormatter = formatters.JsonFormatter;
        var settings = jsonFormatter.SerializerSettings;
        settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
        settings.Formatting = Formatting.Indented;
        settings.ContractResolver = new CamelCasePropertyNamesContractResolver();

        GlobalConfiguration.Configure(WebApiConfig.Register);
    }
}
Run Code Online (Sandbox Code Playgroud)

我通过执行Web服务

http://localhost/api/people?birthday=1980-11-20
Run Code Online (Sandbox Code Playgroud)

但是,返回的是1970年1月1日.进入代码我确认birthday设置为1970-01-01.

如何配置序列化,以便将URL中指定的日期作为查询参数(或路径元素)正确地序列化为NodaTime LocalDate?

Mat*_*int 5

感谢Microsoft提供的这篇非常有用的文章,我能够使用自定义模型绑定器找到解决方案.

将此类添加到项目中:

public class LocalDateModelBinder : IModelBinder
{
    private readonly LocalDatePattern _localDatePattern = LocalDatePattern.IsoPattern;

    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType != typeof (LocalDate))
            return false;

        var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (val == null)
            return false;

        var rawValue = val.RawValue as string;

        var result = _localDatePattern.Parse(rawValue);
        if (result.Success)
            bindingContext.Model = result.Value;

        return result.Success;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后更改您的控制器方法以使用它.

public LocalDate GetPeopleByBirthday(
    [ModelBinder(typeof(LocalDateModelBinder))] LocalDate birthday)
Run Code Online (Sandbox Code Playgroud)

文章还提到了注册模型绑定器的其他方法.

请注意,由于您的方法返回 a LocalDate,您仍然需要Json.net的Noda Time serialziation,因为它最终会在正文中用于返回值.