views:

1912

answers:

3

Hi,

I have an action like this:

public class News : System.Web.Mvc.Controller
{
    public ActionResult Archive(int year)
    {
       / *** /
    }
}

With a route like this:

routes.MapRoute(
           "News-Archive",                                              
           "News.mvc/Archive/{year}",                           
           new { controller = "News", action = "Archive" }
       );

The URL that I am on is:

News.mvc/Archive/2008

I have a form on this page like this:

<form>
    <select name="year">
        <option value="2007">2007</option>
    </select>
</form>

Submitting the form should go to News.mvc/Archive/2007 if '2007' is selected in the form.

This requires the form 'action' attribute to be "News.mvc/Archive".

However, if I declare a form like this:

<form method="get" action="<%=Url.RouteUrl("News-Archive")%>">

it renders as:

<form method="get" action="/News.mvc/Archive/2008">

Can someone please let me know what I'm missing :-)

+2  A: 

You have a couple problems, I think.

First, your route doesn't have a default value for "year", so the URL "/News.mvc/Archive" is actually not valid for routing purposes.

Second, you're expect form values to show up as route parameters, but that's not how HTML works. If you use a plain form with a select and a submit, your URLs will end up having "?year=2007" on the end of them. This is just how GET-method forms are designed to work in HTML.

So you need to come to some conclusion about what's important.

  • If you want the user to be able to select something from the dropdown and that changes the submission URL, then you're going to have to use Javascript to achieve this (by intercepting the form submit and formulating the correct URL).
  • If you're okay with /News.mvc/Archive?year=2007 as your URL, then you should remove the {year} designator from the route entirely. You can still leave the "int year" parameter on your action, since form values will also populate action method parameters.
Brad Wilson
On the right track.See edit comments in question for further details.
Graphain
A: 

I think I've worked out why - the route includes {year} so the generated routes always will too..

If anyone can confirm this?

Graphain
A: 

Solution

Okay here is the solution, (thanks to Brad for leading me there).

1) Require default value in route:

routes.MapRoute(
       "News-Archive",                                              
       "News.mvc/Archive/{year}",                           
       new { controller = "News", action = "Archive", year = 0 }
   );

2) Add a redirect to parse GET parameters as though they are URL segments.

public ActionResult Archive(int year)
{
   if (!String.IsNullOrEmpty(Request["year"]))
   {
       return RedirectToAction("Archive", new { year = Request["year"] });
   }
}

3) Make sure you have your redirect code for Request params before any code for redirecting "default" year entries. i.e.

public ActionResult Archive(int year)
{
   if (!String.IsNullOrEmpty(Request["year"]))
   {
       return RedirectToAction("Archive", new { year = Request["year"] });
   }
   if (year == 0)
   {
       /* ... */
   }
   /* ... */
}

3) Explicitly specify the default value for year in the Url.RouteUrl() call:

Url.RouteUrl("News-Archive", new { year = 0 })
Graphain