4

I'm trying to see if I need to write a custom IHttpRouteConstraint or if I can wrestle with the built-in ones to get what I want. I can't see to find any good documentation on this anywhere.

Basically, here's my action:

[Route("var/{varId:int:min(1)}/slot/{*slot:datetime}")]
public async Task<HttpResponseMessage> Put(int varId, DateTime slot)
{
    ...
}

What I want is to be able to call it like this: PUT /api/data/var/1/slot/2012/01/01/131516 and have the framework bind 19 to var id and a DateTime with a value of "Jan 1st, 2012, 1:15:16pm" as the "slot" value.

Following the guide from here: http://www.asp.net/web-api/overview/web-api-routing-and-actions/create-a-rest-api-with-attribute-routing I am able to get it to work by passing in just the date segments, i.e. PUT /api/data/var/1/slot/2012/01/01 or PUT /api/data/var/1/slot/2012-01-01, but that only gives me a data value, no time components.

Something tells me that trying to pass in time in any sane way through URI segments is a bad idea, but I'm not sure why it'd be a bad idea, besides the ambiguity regarding local vs UTC times.

I've also tried constraining the datetime constraint with a regex, e.g. {slot:datetime:regex(\\d{4}/\\d{2}/\\d{2})/\\d{4})} to try to get it to parse something like 2013/01/01/151617 as a DateTime, but to no avail.

I'm pretty sure I can get this to work with a custom IHttpRouteConstraint, I just don't want to do something that might be built in.

Thanks!

Dimitar Velitchkov
  • 342
  • 2
  • 4
  • 9

2 Answers2

9

an option is to pass the DateTime as query string parameters (see [FromUri]

e.g.

[Route("api/Customer/{customerId}/Calls/")]
public List<CallDto> GetCalls(int customerId, [FromUri]DateTime start, [FromUri]DateTime end)

this will have a signature of

GET api/Customer/{customerId}/Calls?start={start}&end={end}

Create the query string dates with

startDate.ToString("s", CultureInfo.InvariantCulture);

query string will look like

api/Customer/81/Calls?start=2014-07-25T00:00:00&end=2014-07-26T00:00:00
Aaron
  • 1,497
  • 1
  • 12
  • 3
  • `startDate.ToString("s", CultureInfo.InvariantCulture);` what is s in the code ? – Monojit Sarkar Aug 05 '16 at 14:33
  • Just for future reference, the "s" specifies formatting the date to the Sortable Pattern, see: [Microsoft Docs](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings#Sortable) – Pantelis Oct 31 '17 at 11:56
4

Web API datetime constraint doesn't do anything special regarding parsing datetime as you can notice below(source code here). If your request url is like var/1/slot/2012-01-01 1:45:30 PM or var/1/slot/2012/01/01 1:45:30 PM, it seems to work fine...but I guess if you need full flexibility then creating a custom constraint is the best option...

public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection)
{
    if (parameterName == null)
    {
        throw Error.ArgumentNull("parameterName");
    }

    if (values == null)
    {
        throw Error.ArgumentNull("values");
    }

    object value;
    if (values.TryGetValue(parameterName, out value) && value != null)
    {
        if (value is DateTime)
        {
            return true;
        }

        DateTime result;
        string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
        return DateTime.TryParse(valueString, CultureInfo.InvariantCulture, DateTimeStyles.None, out result);
    }
    return false;
}
Kiran
  • 56,921
  • 15
  • 176
  • 161
  • Thanks! I ended up creating my own constraint for this purpose. Turns out its extremely easy. – Dimitar Velitchkov Nov 04 '13 at 16:25
  • Looks like the source code link is about to die due to codeplex shutting down. It seems this has been cloned on Github [here](https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/Common/Routing/Constraints/DateTimeRouteConstraint.cs) – Mr Moose Jul 25 '17 at 03:13