在Web API路由中解析自定义格式的DateTime值

时间:2015-05-05 09:15:56

标签: rest datetime url asp.net-web-api asp.net-web-api2

我想在我的路线中使用DateTime值,如下所示:

/api/items/after/2015-08-01T08:00:00

但由于显而易见的原因,它无法正常工作:

  

System.Web.HttpException:从客户端(:)发现了一个潜在危险的Request.Path值。

我不想逃避:。显然,我需要不同的格式,如2015-08-01T08-00-00,以获得漂亮的网址。它可以通过更改Json.NET中的默认DateTime序列化格式来解决,但在这种情况下,它将全局应用。或者,我可以尝试编写自定义绑定器。我想知道是否有更好(更容易)的方法。也许框架提供了一些开箱即用的配置参数?

1 个答案:

答案 0 :(得分:2)

执行此操作的简单方法如下:

  • 实现一个具有DateTime属性的类,您可以在其中反序列化DateTime值,例如DateTimeWrapper
  • 将路由参数定义为此类,而不是DateTime
  • 创建一个类型转换器,可以通过继承DateTimeWrapper将url段字符串转换为TypeConverter类。你可以称之为DateTimeWrapperConverter
  • 使用类似DateTimeWrapper
  • 的属性装饰您的[TypeConverter(typeof(DateTimeWrapperConverter))]课程

完成此操作后,当您收到请求时,DateTimeWrapper类的任何路由参数都将由您的转换器处理。然后,您只需阅读自定义转换器创建的DateTime的{​​{1}}属性。

通过这种方式,您可以避免修改DateTimeWrapper值的一般行为。

这是一个示例实现,但缺少解析本身:

DateTime

你可以测试这样的控制器:

[TypeConverter(typeof(DateTimeWrapperConverter))]
public class DateTimeWrapper
{
    public DateTime Value { get; set; }
}

public class DateTimeWrapperConverter : TypeConverter
{
    public override bool CanConvertFrom(
       ITypeDescriptorContext context, Type sourceType)
    {
        if (sourceType == typeof (string))
        {
            return true;
        }
        return base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(
         ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value is string)
        {
            DateTimeWrapper wrapper = new DateTimeWrapper
            {
                Value = new DateTime() // parse the url segment !!
            };
            return wrapper;
        }
        return base.ConvertFrom(context, culture, value);
    }
}

由于public class TestController : ApiController { // GET api/<controller>/5 public string Get(DateTimeWrapper id) { return id.Value.ToString(CultureInfo.InvariantCulture); } } 的类型为id,因此会使用自定义转换器进行转换。

如果您愿意,可以更改DateTimeWrapper,使其隐式转换为DateTimeWrapper,这样您就不需要阅读DateTime属性。将其添加到Value类:

DateTimeWrapper

在此之后,只要期望public static implicit operator DateTime(DateTimeWrapper wrapper) { return wrapper.Value; } ,您就可以使用此类的对象。

注意:更改JSON.NET序列化程序在此实例中不执行任何操作。它仅用于反序列化HTTP请求的有效负载,但对路由参数没有任何作用。