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

C# 使用ASP.NET Web API将格式为yyyy MM dd的日期查询参数反序列化为noda time LocalDate对象,c#,asp.net-web-api,nodatime,C#,Asp.net Web Api,Nodatime,我正在研究使用NodaTime LocalDate来替代现有的BCL-DateTime/DateTimeOffset类。由于对DateTime的模糊行为的误解,我们在代码中遇到了许多与时区相关的问题 为了充分利用NodeTime,我希望能够从我们的ASP.NET Web API 2 Web服务发送和接收日期,格式为YYYY-MM-DD。我成功地将LocalDate正确序列化为YYYY-MM-DD。但是,我无法将日期查询参数反序列化为LocalDate。位置日期始终为1970-01-01 以下是我

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

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

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

PeopleController.cs

[RoutePrefix("api")]
public class PeopleController : ApiController
{
    [Route("people")]
    public LocalDate GetPeopleByBirthday([FromUri]LocalDate birthday)
    {
        return birthday;
    }
}
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);
    }
}
Global.asax.cs

[RoutePrefix("api")]
public class PeopleController : ApiController
{
    [Route("people")]
    public LocalDate GetPeopleByBirthday([FromUri]LocalDate birthday)
    {
        return birthday;
    }
}
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);
    }
}
我通过

http://localhost/api/people?birthday=1980-11-20
然而,返回的是1970年1月1日。进入代码,我确认
生日
设置为1970-01-01

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

多亏了,我能够使用自定义模型绑定器找到解决方案

将此类添加到项目中:

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;
    }
}
然后更改控制器方法以使用它

public LocalDate GetPeopleByBirthday(
    [ModelBinder(typeof(LocalDateModelBinder))] LocalDate birthday)
本文还提到了注册模型绑定器的其他方法


请注意,由于您的方法返回一个
LocalDate
,您仍然需要Json.net的Noda时间序列,因为它最终会在主体中用于返回值。

Hmm。如果您删除
FromUri
部分,我不支持它,是吗?(我希望它默认为这个,这可能会让人困惑…)这看起来更像是一个模型解析问题,而不是Noda时间问题——我猜它根本没有进入JSON序列化程序。仅出于诊断目的,您是否尝试过一个具有
LocalDate
类型的
birthday
属性的包装类,然后将该类用作您的参数类型?URL不是JSON,因此它不由JSON.Net解释,也不通过节点时间序列化配置。我可以复制这个。除了在正文中发布之外,我还不确定有什么解决方案,但这对于这个请求来说并不理想。“我会深入挖掘。”JonSkeet,从URI中删除似乎没有什么影响。我用一个
LocalDate Birthday
属性创建了一个
BirthdayFacade
类,该属性也被序列化为1970-01-01.Hmm。让我们希望Matt能有所进展-我在这一点上没有深度。除此之外,本文还讨论了类型转换器的使用。我试过了,但为了注册它,我不得不使用它,这似乎与WebAPI不符。在未来的版本中,是否将类型转换器直接添加到野田佳彦的时间类型中,这可能是值得探索的。它的工作方式很有魅力,并且需要一些优秀的文档来引导。谢谢