【问题标题】:Deserialize a date query parameter of the form yyyy-MM-dd into a noda time LocalDate object using ASP.NET Web API使用 ASP.NET Web API 将 yyyy-MM-dd 形式的日期查询参数反序列化为 noda 时间 LocalDate 对象
【发布时间】:2014-08-31 01:11:18
【问题描述】:

我正在研究使用 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;
    }
}

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);
    }
}

我通过

执行 Web 服务
http://localhost/api/people?birthday=1980-11-20

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

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

【问题讨论】:

  • 嗯。如果您删除 FromUri 部分,我不支持它有帮助,是吗? (我希望它默认为那个,它可能会混淆它......)这看起来更像是一个模型解析问题而不是 Noda Time 问题 - 我的猜测是它根本没有进入 JSON 序列化程序.仅出于诊断目的,您是否尝试过具有 birthday 类型为 LocalDate 的属性的包装类,然后将该类用作您的参数类型?
  • 该 URL 不是 JSON,因此它不会被 JSON.Net 解释,也不会通过 NodaTime 序列化配置。
  • 我可以重现这个。除了在正文中发布之外,我还不确定解决方案,但这对于这个请求并不理想。我会深入挖掘。
  • @JonSkeet,删除 FromUri 似乎没有影响。我创建了一个带有单个 LocalDate Birthday 属性的 BirthdayFacade 类,它也被序列化为 1970-01-01。
  • 嗯。让我们希望马特能得到某个地方 - 我现在已经超出了我的深度。

标签: c# asp.net-web-api nodatime


【解决方案1】:

感谢this very helpful article from 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;
    }
}

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

public LocalDate GetPeopleByBirthday(
    [ModelBinder(typeof(LocalDateModelBinder))] LocalDate birthday)

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

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

【讨论】:

  • 除此之外,本文还讨论了类型转换器的使用。我试过了,但要注册它我必须使用this technique,这似乎与 WebAPI 不一致。在未来的版本中是否将类型转换器直接添加到 Noda Time 类型可能值得探索。
  • 工作起来就像一个魅力,并带有一些优秀的文档来引导。谢谢!
猜你喜欢
  • 1970-01-01
  • 2017-07-20
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 2014-05-30
  • 2013-10-19
  • 2013-03-18
相关资源
最近更新 更多