Reputation: 15159
I'd like to use DateTime
values in my routes like this:
/api/items/after/2015-08-01T08:00:00
but it's not working for the obvious reason:
System.Web.HttpException: A potentially dangerous Request.Path value was detected from the client (:).
I don't want to escape :
. Apparently, I need different format like 2015-08-01T08-00-00
for nice looking urls. It can be solved by changing default DateTime
serialization format in Json.NET but in this case it will be applied globally. Or, I can try writing a custom binder. I wonder if there is a better (easier) approach. Maybe some configuration parameter the framework offers out of the box?
Upvotes: 2
Views: 784
Reputation: 39045
The easies way to do this id the following:
DateTimeWrapper
DateTime
DateTimeWrapper
class, by inheriting from TypeConverter
. You can call it DateTimeWrapperConverter
DateTimeWrapper
class with an attribute like this [TypeConverter(typeof(DateTimeWrapperConverter))]
Once you've done this, when you receive the request, any route parameter of DateTimeWrapper
class will be handled by your converter. Then you simply have to read the DateTime
property of the DateTimeWrapper
created by your custom converter.
In this way you avoid modifying the general behaviour for DateTime
values.
This is a sample implementation, but the parsing itself is missing:
[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);
}
}
You can test is wit a controller like this:
public class TestController : ApiController
{
// GET api/<controller>/5
public string Get(DateTimeWrapper id)
{
return id.Value.ToString(CultureInfo.InvariantCulture);
}
}
As the id
is of type DateTimeWrapper
it's converted with the custom converter.
If you want you can change the DateTimeWrapper so that it has an implicit convertion to DateTime
, so that you don't need to read the Value
property. Add this to the DateTimeWrapper
class:
public static implicit operator DateTime(DateTimeWrapper wrapper)
{
return wrapper.Value;
}
After this you can use an object of this class whenever a DateTime
is expected.
NOTE: changing the JSON.NET serializer would do nothing in this instance. It's only used to deserialize the payload of the HTTP request, but does nothing about the route parameters.
Upvotes: 2