Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating an ActionLink with a DateTime in the query string in ASP.NET MVC

Tags:

asp.net-mvc

I have a search form with a DateTime search criterion, plus some other criteria:

<form method="get" action="/app/search">
    <input type="text" value="13/01/2010" name="BeginDate"/>
    <input type="text" value="blah" name="SomeOtherCriterion"/>
<form>

So I have a Search controller with a default Action (let's call it Index) and with a SearchCriteria parameter.

public class SearchController
{
    public ActionResult Index(SearchCriteria searchCriteria) {//blah }
}    

public class SearchCriteria
{
    public DateTime BeginDate {get; set;}
    public string SomeOtherCriterion {get; set;}
}

Now if I want to create an ActionLink, passing in a SearchCriteria value, thus:

Html.ActionLink("Search", "Index", searchCriteria)

I get the BeginDate query string parameter in US format. Looking on Google and poking around in System.Web.Routing using Reflector it seems to be because it uses the InvariantCulture, so there's nothing I can do about it.

It seems like noone has asked this question before so I guess I'm doing something very stupid.... Please help!

EDIT: Pass in SearchCriteria to ActionLink rather than anonymous object to show why I can't just do the custom ToString() myself.

like image 654
Gaz Avatar asked Jan 07 '10 17:01

Gaz


2 Answers

Given that the framework appears to be hard-coded to handle this piece of data using InvariantCulture, I don't think there's much you can do to make it work transparently.

There is one ugly option - download the MVC source and rip out the code for all the offending classes from Route down to ParsedRoute to create your own RouteBase implementation that does what you need.

If I absolutely had to keep the DateTime declaration on the SearchCriteria class, then that's the route (sorry for the pun) I would choose.

However, a far easier solution would be to change your SearchCriteria class to use a slightly different declaration for the DateTime field, based on a type like this:

public class MyDateTime
{
  public DateTime Value { get; set; }
  //for passing MyDateTime in place of a DateTime without casting
  public static implicit operator DateTime(MyDateTime instance) { return instance.Value; }
  //so you can assign a MyDateTime from a DateTime without a cast
  //- e.g. MyDateTime dt = DateTime.Now
  public static implicit operator MyDateTime(DateTime instance) { return new MyDateTime() { Value = instance }; }
  //override ToString so that CultureInfo.CurrentCulture is used correctly.
  public override string ToString()
  {
    return Value.ToString(CultureInfo.CurrentUICulture);
  }
}

In theory you should be able to roll out this change without too much fuss.

The big work could be if you have a lot of code that uses members (e.g. .Days etc) of the DateTime instance in SearchCriteria: you either have to reproduce those members on MyDateTime, wrapping around the inner DateTime Value or change all the code to use .Value.Member.

like image 50
Andras Zoltan Avatar answered Oct 12 '22 23:10

Andras Zoltan


To avoid issues related to Regional Settings and "Culture", I treat date and time as separate unbound fields and then assemble them into DateTime in my Controller.

Example:

Year [ ] Month [ ] Day [ ]

I always present separate textboxes for year, month, and day, in that order so that there can be no confusion between U.S. format (month/day/year) and more or less the rest of the world's format (day/month/year).

like image 27
gerryLowry Avatar answered Oct 12 '22 22:10

gerryLowry