MVC Routing issue: null entry - c#

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.

Related

Is it possible to host Asp.net MVC web App locally [duplicate]

In asp.net MVC the "homepage" (ie the route that displays when hitting www.foo.com) is set to Home/Index .
Where is this value stored?
How can I change the "homepage"?
Is there anything more elegant than using RedirectToRoute() in the Index action of the home controller?
I tried grepping for Home/Index in my project and couldn't find a reference, nor could I see anything in IIS (6). I looked at the default.aspx page in the root, but that didn't seem to do anything relevent.
Thanks
Look at the Default.aspx/Default.aspx.cs and the Global.asax.cs
You can set up a default route:
routes.MapRoute(
"Default", // Route name
"", // URL with parameters
new { controller = "Home", action = "Index"} // Parameter defaults
);
Just change the Controller/Action names to your desired default. That should be the last route in the Routing Table.
ASP.NET Core
Routing is configured in the Configure method of the Startup class. To set the "homepage" simply add the following. This will cause users to be routed to the controller and action defined in the MapRoute method when/if they navigate to your site’s base URL, i.e., yoursite.com will route users to yoursite.com/foo/index:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=FooController}/{action=Index}/{id?}");
});
Pre-ASP.NET Core
Use the RegisterRoutes method located in either App_Start/RouteConfig.cs (MVC 3 and 4) or Global.asax.cs (MVC 1 and 2) as shown below. This will cause users to be routed to the controller and action defined in the MapRoute method if they navigate to your site’s base URL, i.e., yoursite.com will route the user to yoursite.com/foo/index:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Here I have created a custom "Default" route that will route users to the "YourAction" method within the "FooController" controller.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "FooController", action = "Index", id = UrlParameter.Optional }
);
}
Step 1: Click on Global.asax File in your Solution.
Step 2: Then Go to Definition of
RouteConfig.RegisterRoutes(RouteTable.Routes);
Step 3: Change Controller Name and View Name
public class RouteConfig
{
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 }
);
}
}
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Your Controller", action = "Your Action", id = UrlParameter.Optional }
);
}
}
Attribute Routing in MVC 5
Before MVC 5 you could map URLs to specific actions and controllers by calling routes.MapRoute(...) in the RouteConfig.cs file. This is where the url for the homepage is stored (Home/Index). However if you modify the default route as shown below,
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
keep in mind that this will affect the URLs of other actions and controllers. For example, if you had a controller class named ExampleController and an action method inside of it called DoSomething, then the expected default url ExampleController/DoSomething will no longer work because the default route was changed.
A workaround for this is to not mess with the default route and create new routes in the RouteConfig.cs file for other actions and controllers like so,
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Example",
url: "hey/now",
defaults: new { controller = "Example", action = "DoSomething", id = UrlParameter.Optional }
);
Now the DoSomething action of the ExampleController class will be mapped to the url hey/now. But this can get tedious to do for every time you want to define routes for different actions. So in MVC 5 you can now add attributes to match urls to actions like so,
public class HomeController : Controller
{
// url is now 'index/' instead of 'home/index'
[Route("index")]
public ActionResult Index()
{
return View();
}
// url is now 'create/new' instead of 'home/create'
[Route("create/new")]
public ActionResult Create()
{
return View();
}
}
check RegisterRoutes method in global.asax.cs - it's the default place for route configuration...
I tried the answer but it didn't worked for me. This is what i ended up doing:
Create a new controller DefaultController. In index action, i wrote one line redirect:
return Redirect("~/Default.aspx")
In RouteConfig.cs, change controller="Default" for the route.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Default", action = "Index", id = UrlParameter.Optional }
);
If you don't want to change the router, just go to the HomeController
and change MyNewViewHere in the index like this:
public ActionResult Index()
{
return View("MyNewViewHere");
}

Custom URL Routing in Asp.Net MVC 4

How can i do like this url (http://www.domain.com/friendly-content-title) in Asp.Net MVC 4.
Note: This parameter is always dynamic. URL may be different: "friendly-content-title"
I try to Custom Attribute but I dont catch this (friendly-content-title) parameters in ActionResult.
Views:
Home/Index
Home/Video
ActionResult:
// GET: /Home/
public ActionResult Index()
{
return View(Latest);
}
// GET: /Home/Video
public ActionResult Video(string permalink)
{
var title = permalink;
return View();
}
RouteConfig:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Home Page",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Video Page",
url: "{Home}/{permalink}",
defaults: new { controller = "Home", action = "Video", permalink = "" }
);
}
What should I do for catch to url (/friendly-content-title)?
To enable attribute routing, call MapMvcAttributeRoutes during configuration. Following are the code snipped.
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
}
}
In MVC5, we can combine attribute routing with convention-based routing. Following are the code snipped.
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 }
);
}
It is very easy to make a URI parameter optional by adding a question mark to the route parameter. We can also specify a default value by using the form parameter=value. here is the full article.
Radim Köhler's solution is a good one.
But another option if you want more control over routing is using a custom constraint.
Here's an example
RouteConfig.cs
routes.MapRoute(
"PermaLinkRoute", //name of route
"{*customRoute}", //url - this pretty much catches everything
new {controller = "Home", action = "PermaLink", customRoute = UrlParameter.Optional},
new {customRoute = new PermaLinkRouteConstraint()});
So then on your home controller you could have action like this
HomeController.cs
public ActionResult PermaLink(string customRoute)
{
//customRoute would be /friendly-content-title..do what you want with it
}
The magic of this happens in the IRouteConstraint that we specified as the 4th argument in the MapRoute call.
PermaLinkRouteConstraint.cs
public class PermaLinkRouteConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values,
RouteDirection routeDirection)
{
var permaRoute = values[parameterName] as string;
if (permaRoute == null)
return false;
if (permaRoute == "friendly-content-title")
return true; //this indicates we should handle this route with our action specified
return false; //false means nope, this isn't a route we should handle
}
}
I just wanted to show a solution like this to show you can basically do anything you want.
Obviously this would need to be tweaked. Also you'd have to be careful not to have database calls or anything slow inside the Match method, as we set that to be called for every single request that comes through to your website (you could move it around to be called in different orders).
I would go with Radim Köhler's solution if it works for you.
What we would need, is some marker keyword. To clearly say that the url should be treated as the dynamic one, with friendly-content-title. I would suggest to use the keyword video, and then this would be the mapping of routes:
routes.MapRoute(
name: "VideoPage",
url: "video/{permalink}",
defaults: new { controller = "Home", action = "Video", permalink = "" }
);
routes.MapRoute(
name: "HomePage",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
Now, because VideoPage is declared as the first, all the urls (like these below) will be treated as the dynamic:
// these will be processed by Video action of the Home controller
domain/video/friendly-content-title
domain/video/friendly-content-title2
while any other (controllerName/ActionName) will be processed standard way

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.

How to route request to www.MyDomain.com to specific controller class and method

In my MVC application, when user goes to www.MyDomain.com/Home, this request is processed in HomeController class Index method due to following routing entry in Global.asax
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Let's say if user goes to www.MyDomain.com/SomeParameters, I want this request to be processed in MyController class Index method. An example for the parameters will be www.MyDomain.com/John. For this I have created following entry in Global.asax but it does not seem to get hit. Can anyone point out what I am doing wrong here?
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "MyController", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
The routing handles John as the controller, not the action. So in your example John is the controller and because you don't provide an action, it takes Index as the default action.
If you want www.MyDomain.com/John to be routed to controller MyController, action Index and a parameter that contains John, a solution could be to add the following route (before the default route):
routes.MapRoute(
name: "MyController",
url: "{myparameter}",
defaults: new { Controller = "MyController", Action = "Index" });
And the controller:
public ActionResult Index(string myparameter)
{
return View("whatever");
}
This will lead www.MyDomain.com/John to the Index action with myparameter = "John".
ps. In the example myparameter is mandatory.
In order to have www.MyDomain.com/SomeParameters you simply need to create a route where the Controller and the Action method are defaulted since they will not be provided in the URL.
Make sure the route definition only includes the someparameters and does not have anything else. This way you can just treat anything in the URL after / as a parameter.
routes.MapRoute(
name: "MyController",
url: "{someparameters}",
defaults: new { Controller = "MyController", Action = "Index" });
public ActionResult Index(string someparameters)
{
...
return View();
}

URL Parameter Not Recognized in Controller

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.

Categories