URL Parameter Not Recognized in Controller - c#

I'm learning MVC 4, and it's my understanding that going to this URL should pass an int of 44 to the Edit() method of the controller. Indeed, when I go here:
http://localhost:51921/TrackerJob/Edit/44
... this method gets invoked:
public ActionResult Edit(int trackerJobId = -1)
{
Debug.WriteLine(trackerJobId);
}
... but the parameter is always -1. I had this working in a different project, but for some reason it's always -1 in this project. I don't see a difference between the two projects that would cause one to work and this one to fail. If I change the method signature to this:
public ActionResult Edit(int trackerJobId)
{
Debug.WriteLine(trackerJobId);
}
I get an error:
The parameters dictionary contains a null entry for parameter 'trackerJobId' of non-nullable type 'System.Int32'
Any ideas? I'm not sure what to check...
Edit - Including routes, by request*
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}

If you want to use the default routing then just make sure your parameter is called id.
Otherwise you could add a new route like this:
routes.MapRoute(
name: "TrackerJob",
url: "{controller}/{action}/{jobtrackerid}",
defaults: new { controller = "TrackerJob", action = "Index", id = UrlParameter.Optional }
);
Make sure you add this route BEFORE the default route. The order of routes is very important!
Only you know if the trackerJobId is optional or not.
Note that if you want something more fancy you can tweak the routes to produce what you want.
e.g. If you want URLs like http://localhost:51921/TJ-E-44 for editing then your route would look like this:
routes.MapRoute(
name: "TrackerJobEdit",
url: "TJ-E-{jobtrackerid}",
defaults: new { controller = "TrackerJob", action = "Edit", id = UrlParameter.Optional }
);
I'm sure you get the idea.

Related

MVC Uri Parameter is null

When attempting to pass a parameter to a simple controller I receive the parameter as always being null.
Controller
public class GetOrgController : Controller
{
private DirectoryEntities de;
public getOrgController()
{
de = new DirectoryEntities();
}
// GET: getOrg
public ActionResult Index(string district)
{
getorg_Result org = de.getorg(district).FirstOrDefault();
return View(org);
}
}
When I try to navigate to that url with a parameter localhost:660366/GetOrg/Index/D123 the district variable is always null.
I thought maybe it had to do something with the default RouteConfig. When I put a new value ahead of the default route config it worked! However now, whenever I try to launch the application it goes to the GetOrgController first. What happens when I want a new controller with different parameters? I have to do this every time? Here is my new RouteConfig with the new entry.
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "GetOrg",
url: "{controller}/{action}/{district}",
defaults: new { controller = "GetOrg", action = "Index", district = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I actually started doing Rest initially in Web Api 2, but the view-model attracted me to MVC. It is a lot easier specifiying above the method the routes/parameters I wanted like below. Is this possible in MVC?
WebApi2
[Route("Index/{district}")]
public ActionResult Index(string district)
{
getorg_Result orgs = de.getorg(district).FirstOrDefault();
return View(orgs);
}
The above method seems so much cleaner than having to rely on the order of controllers being correct in the RouteConfig
These two routes literally make no sense. The first one says, for ANY controller with ANY method default to GetOrgController. That isn't what you want because now id won't work for all the other controllers and the second MapRoute is close to a duplicate.
routes.MapRoute(
name: "GetOrg",
url: "{controller}/{action}/{district}",
defaults: new { controller = "GetOrg", action = "Index", district = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
What you really should be doing is saying for any call starting with GetOrg then call GetOrgController for any method....
routes.MapRoute(
name: "GetOrg",
url: "GetOrg/{action}/{district}",
defaults: new { controller = "GetOrg", action = "Index", district = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
thats because both routs are generic thats why it hits the first route by default so you can remove UrlParameter.Optional so that the route should be a little specific
routes.MapRoute(
name: "GetOrg",
url: "{controller}/{action}/{district}",
defaults: new { controller = "GetOrg", action = "Index"}
);
but still you can use the default route for that purpose no need of additional route unless you want to use a custom url like random/234

MVC Routing issue: null entry

I have this Controller:
public class TestController : Controller
{
// GET: Test
public ActionResult Index()
{
return View();
}
public ActionResult Edit(int accessLevel)
{
return View();
}
}
Set up in RouteConfig.cs as:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Test Edit",
url: "Test/Edit/{accessLevel}",
defaults: new { controller = "Test", action = "Edit", accessLevel = UrlParameter.Optional }
);
If I go to this URL:
http://localhost:35689/Test/Edit/2
I get this error:
The parameters dictionary contains a null entry for parameter
'accessLevel' of non-nullable type 'System.Int32' for method
'System.Web.Mvc.ActionResult Edit(Int32)' in
'MyProject.Mvc.Client.Controllers.TestController'. An optional
parameter must be a reference type, a nullable type, or be declared as
an optional parameter. Parameter name: parameters
Any idea why that is? I would think that I'm providing the right datatype with /2.
The specific route definition should be defined before the generic default one.The order of route definitions really matters.
routes.MapRoute(
name: "Test Edit",
url: "Test/Edit/{accessLevel}",
defaults: new { controller = "Test", action = "Edit",
accessLevel = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
);
If you keep the other order like what you have (Generic-default first ,specific one later), When a request comes for Test/Edit/2 It will be matched to the generic route definition because Test is a valid controller and Edit is a valid action method name and 2 could be a valid param value for Id param.
Since the request got a valid route definition to match to it's url pattern, It will never be evaluated against other route definitions defined below the first one.
Keep all specific route definitions first and have the generic-default one as the very last one.
Or You may use attribute routing to define this route pattern in the Test controller.To enable attribute routing, you can call the MapMvcAttributeRoutes method in the RegisterRoutes method of RouteConfig.cs. You will still keep the default route definition there.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
and in your TestController
[Route("Test/Edit/{id?}")]
public ActionResult Edit(int? id)
{
//check id value and return something
}
Also, there is no point in defining a custom route if it matches with the generic default route definition. In your case, Even if you do not define the custom route ,Test/Edit/2 will go to the Edit action method of TestController as the request matches the default route definition.
People usually use these custom route definition to create nice url patterns like
[Route("Product/{id}/{name}")]
public ActionResult View(int id,string name)
{
//check id value and return something
}
This route definition will match the request Product/34/seo-friendly-name. Take a look at the URL of this question and you will understand what i am explaining here.
Switch the routes in RoutesConfig.cs. They should go from the most specific to general.
Your Default route is catching this one.
Please interchange your Route in RouteConfig becuase Order of routes are really matters a lot.

MVC calling different method with same parameters

I have a Controller that have 2 method with same parameters But if I call it I got an error
Several actions that matched the request were found:
I think that I must change Map routing to accomplish that but I dont know how to do it
My methods :
public IHttpActionResult RecuperarMenu(short idInstalacion,string secretKey)
public IHttpActionResult RecuperarClasesColectivas(short idInstalacion, string secretKey)
My route map
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional,
namespaces = new[] { "WebServicesRestAPI.Controllers" }
}
);
//routes.MapRoute(
// name: "Default",
// url: "{controller}/{action}/{id}",
// defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
//);
}
I guess the controller that contains your methods is a WebAPI controller (it is derived from the ApiController class). Correct?
Thus, being a WebAPI controller:
It is configured not by means of the MapRoute method, but by means of the HttpConfiguration.Routes.MapHttpRoute method (by default it is configured in the ~/App_Start/WebApiConfig.cs file):
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
The names within the controller should follow the GET/POST/PUT/DELETE pattern (or should be explicitly mapped by you).
If your methods correspond to the GET operation, they should differ by arguments (you have the same arguments if your methods).

How to change parameter name in controller in MVC4?

I have a Controller like following:
public class PostsController : Controller
{
public ActionResult Index(int CategoryID)
{
return Content(CategoryID.ToString());
}
}
And my router is:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I wants add a MapRoute into RegisterRoutes like this:
routes.MapRoute(
name: "Posts",
url: "Posts/{action}/{CategoryID}",
defaults: new { controller = "Posts", action = "Index", CategoryID = UrlParameter.Optional }
);
I go to /Posts/Index/1 url but I give following error:
The parameters dictionary contains a null entry for parameter 'CategoryID' of non-nullable type 'System.Int32'
Note: in controller if I change CategoryID to id problem solved, and it worked!
As #Davide Icardi said, you need to place your new route above the default route.
Routes are evaluated from first to last; the first one to match will be used. Placing the route specific to the Posts controller at the top of the list will guarantee that it is matched before the default route.

MVC4 Route as /{controler}-{id} instead of /{controler}/{id}

During my work I must solve one URL rewriting problem. I have to use URLs as a template:
{controller}/{action}-{id}
instead of
{controller}/{action}/{id}
so the processed url should look like:
myController/myAction-128
where 128 is a parameter
My route map:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "NewRoute", // Route name
url: "{controller}/{action}-{id}/{extId}", // URL with parameters
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional, extId = UrlParameter.Optional } // Parameter defaults
);
}
Controller code:
[HttpGet]
public ActionResult DocumentDetails(int? id)
{
if (doc.HasValue)
{
...
}
}
This route doesn't provide any successful results. I still have 404 Errors. When I use / instead of "-" everything is ok, but my JS View environment won't work.
Is there something I could do to fix this? All help will be appreciated, thanks.
Routes are evaluated in the same order as you defined them, so make sure you respect the same order. Also adding a constraint for the id (as being a number for example) would help the routing engine disambiguate your routes. Not to mention that in your example you have made the id token optional which of course is not possible, only the last part of a route can be optional.
So:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "NewRoute",
url: "{controller}/{action}-{id}/{extId}",
defaults: new { controller = "Home", action = "Index", extId = UrlParameter.Optional },
new { id = #"\d+" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I'm thinking your request is being processes by the first routing rule and then action-id is considered as a whole action and not being found.
Set your NewRoute before the Default route. Just move the code up.

Categories