113

I have a controller with an action method as follows:

public class InventoryController : Controller
{
    public ActionResult ViewStockNext(int firstItem)
    {
        // Do some stuff
    }
}

And when I run it I get an error stating:

The parameters dictionary does not contain a valid value of type 'System.Int32' for parameter 'firstItem'. To make a parameter optional its type should either be a reference type or a Nullable type.

I had it working at one point and I decided to try the function without parameters. Finding out that the controller was not persistant I put the parameter back in, now it refuses to recognise the parameter when I call the method.

I'm using this url syntax to call the action:

http://localhost:2316/Inventory/ViewStockNext/11

Any ideas why I would get this error and what I need to do to fix it?

I've tried adding another method that takes an integer to the class it it also fails with the same reason. I've tried adding one that takes a string, and the string is set to null. I've tried adding one without parameters and that works fine, but of course it won't suit my needs.

tereško
  • 58,060
  • 25
  • 98
  • 150
Odd
  • 4,737
  • 6
  • 30
  • 27

10 Answers10

112

Your routing needs to be set up along the lines of {controller}/{action}/{firstItem}. If you left the routing as the default {controller}/{action}/{id} in your global.asax.cs file, then you will need to pass in id.

routes.MapRoute(
    "Inventory",
    "Inventory/{action}/{firstItem}",
    new { controller = "Inventory", action = "ListAll", firstItem = "" }
);

... or something close to that.

Jarrett Meyer
  • 19,333
  • 6
  • 58
  • 52
  • 45
    Or just rename "firstItem" to "id" – Kyle Trauberman Feb 06 '09 at 16:01
  • 8
    Plus it world be wise to add a constraints object to the MapRoute, like so: `new { firstItem = @"\d" }`. This way it will **only** accept if the parameter is any kind of number. You can modify the regex as you like, and even limit the number of decimals, like this: `new { firstItem = @"\d{4}" }` - now it can only be 4 numbers long. Edit: example of fully modified MapRoute: http://jsfiddle.net/HJRgT/ – KristianB Sep 18 '11 at 16:57
89

you can change firstItem to id and it will work

you can change the routing on global.asax (i do not recommed that)

and, can't believe no one mentioned this, you can call :

http://localhost:2316/Inventory/ViewStockNext?firstItem=11

In a @Url.Action would be :

@Url.Action("ViewStockNext", "Inventory", new {firstItem=11});

depending on the type of what you are doing, the last will be more suitable. Also you should consider not doing ViewStockNext action and instead a ViewStock action with index. (my 2cents)

Bart Calixto
  • 19,210
  • 11
  • 78
  • 114
15

To rephrase Jarret Meyer's answer, you need to change the parameter name to 'id' or add a route like this:

routes.MapRoute(
        "ViewStockNext", // Route name
        "Inventory/ViewStockNext/{firstItem}",  // URL with parameters
        new { controller = "Inventory", action = "ViewStockNext" }  // Parameter defaults
    );

The reason is the default route only looks for actions with no parameter or a parameter called 'id'.

Edit: Heh, nevermind Jarret added a route example after posting.

Community
  • 1
  • 1
Matt Mitchell
  • 40,943
  • 35
  • 118
  • 185
12

or do it with Route Attribute:

public class InventoryController : Controller
{
    [Route("whatever/{firstItem}")]
    public ActionResult ViewStockNext(int firstItem)
    {
        int yourNewVariable = firstItem;
        // ...
    }
}
Stephen Reindl
  • 5,659
  • 2
  • 34
  • 38
Yar
  • 7,020
  • 11
  • 49
  • 69
  • This property may not be work with older MVC versions. – Suat Atan PhD Jun 01 '17 at 14:05
  • Also, for this to work you need to ensure you have called `routes.MapMvcAttributeRoutes();` within the application's `RegisterRoutes(RouteCollection)` method (usually scaffolded into App_Start\RouteConfig.cs). It may not be in there by default. – Daniel Scott Dec 14 '19 at 22:04
8

Headspring created a nice library that allows you to add aliases to your parameters in attributes on the action. This looks like this:

[ParameterAlias("firstItem", "id", Order = 3)]
public ActionResult ViewStockNext(int firstItem)
{
    // Do some stuff
}

With this you don't have to alter your routing just to handle a different parameter name. The library also supports applying it multiple times so you can map several parameter spellings (handy when refactoring without breaking your public interface).

You can get it from Nuget and read Jeffrey Palermo's article on it here

Matthew Nichols
  • 4,866
  • 4
  • 41
  • 48
8

Using the ASP.NET Core Tag Helper feature:

<a asp-controller="Home" asp-action="SetLanguage" asp-route-yourparam1="@item.Value">@item.Text</a>
Sasha Yakobchuk
  • 471
  • 6
  • 12
7

public ActionResult ViewNextItem(int? id) makes the id integer a nullable type, no need for string<->int conversions.

Mahmoud Gamal
  • 78,257
  • 17
  • 139
  • 164
Oskar Duveborn
  • 2,189
  • 16
  • 20
1

There is another way to accomplish that (described in more details in Stephen Walther's Pager example

Essentially, you create a link in the view:

Html.ActionLink("Next page", "Index", routeData)

In routeData you can specify name/value pairs (e.g., routeData["page"] = 5), and in the controller Index function corresponding parameters receive the value. That is,

public ViewResult Index(int? page)

will have page passed as 5. I have to admit, it's quite unusual that string ("page") automagically becomes a variable - but that's how MVC works in other languages as well...

Felix
  • 9,248
  • 10
  • 57
  • 89
0

Or, you could try changing the parameter type to string, then convert the string to an integer in the method. I am new to MVC, but I believe you need nullable objects in your parameter list, how else will the controller indicate that no such parameter was provided? So...

public ActionResult ViewNextItem(string id)...
BenMorel
  • 34,448
  • 50
  • 182
  • 322
RAL
  • 917
  • 8
  • 19
0

The reason for the special treatment of "id" is that it is added to the default route mapping. To change this, go to Global.asax.cs, and you will find the following line:

routes.MapRoute ("Default", "{controller}/{action}/{id}", 
                 new { controller = "Home", action = "Index", id = "" });

Change it to:

routes.MapRoute ("Default", "{controller}/{action}", 
                 new { controller = "Home", action = "Index" });
Aristoteles
  • 708
  • 2
  • 7
  • 15