I'm kind of new to MVC. I have a controller called PostItemsController in an area called CaseManagers with an action method called GetByUmi(int caseNumber):
[HttpGet]
public ViewResult ViewByUmi(int umi)
{
//implementation omitted
}
The routing configuration looks like this (not my work):
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
//ignore route for ico files
routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?../Images/MauriceFavicon.ico(/.*)?" });
routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*开发者_运维知识库/)?Images/MauriceFavicon.ico(/.*)?" });
routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?Content/Images/MauriceFavicon.ico(/.*)?" });
routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?/favicon.ico(/.*)?" });
//ignore javascript files routing
routes.IgnoreRoute("{file}.js");
//ignore routing for files ending .doc
routes.IgnoreRoute("{resource}.doc");
routes.MapRoute(
"CaseManagers", // Route name
"CaseManagers/PostItems/ViewByUmi/{id}", // URL with parameters
new { controller = "PostItems" } // Parameter defaults
);
//InvoicesLookUp route
routes.MapRoute(
"InvoicesLookUpShortDefault", // Route name
"InvoicesLookUp/{action}/{id}", // URL with parameters
new { controller = "InvoicesLookUp", action = "Index", area = "Home", id = UrlParameter.Optional } // Parameter defaults
,
null,
new[] { "MooseMvc.Areas.Accounts.Controllers" } // Parameter defaults
).DataTokens.Add("area", "Accounts");
//Invoices route
routes.MapRoute(
"InvoicesShortDefault", // Route name
"Invoices/{action}/{id}", // URL with parameters
new { controller = "Invoices", action = "Index", area = "Accounts", id = UrlParameter.Optional } // Parameter defaults
,
null,
new[] { "MooseMvc.Areas.Accounts.Controllers" } // Parameter defaults
).DataTokens.Add("area", "Accounts");
//administrating route
routes.MapRoute(
"AdministratorShortDefault", // Route name
"Administrator/{action}/{id}", // URL with parameters
new { controller = "Administrator", action = "Index", area = "Administrator", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
//add root route route
routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "Index", id = "" }
);
When I try to call this method with the URL http://localhost:[portnumber]/CaseManagers/PostItems/ViewByUmi/1234
I get the following exception:
The parameters dictionary contains a null entry for parameter 'umi' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ViewResult ViewByUmi(Int32)' in 'MooseMvc.Areas.CaseManagers.Controllers.PostItemsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
I don't intend the ID parameter to be optional and I don't understand why MVC can't find the ID.
Can anyone tell me what I need to do?
EDIT:
Phil Haack's route tester is telling me that the following route is being mapped:
routes.MapRoute(
"CaseManagers", // Route name
"CaseManagers/PostItems/ViewByUmi/{id}", // URL with parameters
new { controller = "PostItems" } // Parameter defaults
);
But it is being mapped AFTER another route CaseManagers/{controller}/{action}/{id}
. But this route isn't anywhere in the Global.asax file (take a look, it's reproduced in full above).
Any idea what's going on?
Method parameters in ASP.NET MVC match up 1-1 with route parameters. Since you have no routes that take in a route value named umi
, no route will catch what you're trying to do.
You have one of two choices:
- If you want the default route to handle that action, then change:
public ViewResult ViewByUmi(int umi)
{
//implementation omitted
}
to:
public ViewResult ViewByUmi(int id)
{
//implementation omitted
}
However, if you want to keep umi
(because it has contextual meaning that makes that code easier to follow), then you want to add a route to explicitly deal with it:
//UMI route
routes.MapRoute(
"umi",
"/case/postitems/view/{umi}",
new { area = "CaseManager", controller = "PostItems", action = "ViewByUmi", umi = "" }
);
Turns out that Global.asax isn't the only place that routing happens. Each of the areas in this application has its AreaRegistration class. I added a new route to the top of this class to produce the following:
public class CaseManagersAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "CaseManagers";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"PostItems", // Route name
"CaseManagers/PostItems/ViewByUmi/{umi}", // URL with parameters
new { area = "CaseManagers", controller = "PostItems", action = "GetByUmi", umi = "{umi}" } // Parameter defaults
);
context.MapRoute(
"CaseManagers_default",
"CaseManagers/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
The routing debugger now tells me this is getting matched first. Now I just need to work out why I've got an error telling the the resource cannot be found...
You don't have a route for CaseManagers/PostItems/ViewByUmi/1234
and it would appear that it is taking ViewByUmi
and try to convert it to an System.Int32
because it is falling into the Default
route. If you create a Route
for your CaseManagers
you should no longer have this problem.
Use Phil Haacks' Route Debugger to help you out :o)
routes.MapRoute(
"CaseManagers", // Route name
"CaseManagers/PostItems/ViewByUmi/{id}", // URL with parameters
new { controller = "PostItems" } // Parameter defaults
);
精彩评论