I'm trying to utilize the HTML.ActionLinks in MVC. I have a route definition like so:
routes.MapRoute(
name: "RestaurantCommon",
url: "Rest/{siteName}/Admin/{action}/{id}",
defaults: new { controller = "AdminCommon", action = "Promotions", id = UrlParameter.Optional }
);
Is it possible to use ActionLinks to keep the "Rest" and "Admin" in the folder structure? Below is what I have. It works but doesn't keep the pattern I want (it works because of a default below the one I defined above)
<li>#Html.ActionLink("Burger Star", "Promotions", "AdminCommon", new { siteName="BurgerStar" }, null)</li>
Use #RouteLink
#Html.RouteLink("Burger Star", "RestaurantCommon", new { siteName = "BurgerStar" })
Related
I am not an advanced developer. I just started working with MVC. Few days back I had seen an example of ASP.NET MVC routing code where two controller or action name has been referenced.
routes.MapRoute(
name: "test",
url: "{controller}/{action}/{page}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
defaults: new { action = "Index" }
);
Just started working with ASP.NET MVC, so I am curious to know what is the objective to mention controller or action name twice in routing code?
In above example there are two defaults.... When and why is it required?
Just requesting some one to explain the same with a nice example.
Thanks in advance.
The example from the link you posted:
context.MapRoute(
"UserHome",
"User/{id}",
new { action = "Index", controller = "Home", area = "User", id = 0,
httproute = true },
new { controller = #"Home", id = #"\d+" }
);
is a bit confusing, because it is using anonymous types without named arguments. If you add named arguments to that example, it would look like this:
context.MapRoute(
name: "UserHome",
url: "User/{id}",
defaults: new { action = "Index", controller = "Home", area = "User", id = 0,
httproute = true },
constraints: new { controller = #"Home", id = #"\d+" }
);
This makes it more clear what is going on here. The example is not showing two sets of defaults, instead there are constraints that limit the range of values that will match.
It basically says:
controller = #"Home" - When generating the URL, only match this route if controller route value is Home.
id = #"\d+" - Match if the id route value contains only numerals.
Actually, both of the above constraints run for both incoming URL matching and URL generation, but controller = #"Home" will always be true when matching the incoming URL because the default value is the only thing that can set it (and the default value is also Home).
I'm trying to simplify the URLs in an application, and am struggling with the route registration. This is an administrative tool. In many cases we have a List view (List.cshtml) and a Details view (Index.cshtml). The pattern that I would like to implement for these URLs are as follows:
http://mysite/person/list (This view shows a list of people)
http://mysite/person/123 (View will show details for a person with an ID of 123)
Formatting the URls that way is more of a nice-to-have feature for polishing the site. I tried several routes, and in RouteConfig here are some of the more recent routes that I've tried.
routes.MapRoute(
name: "Person",
url: "Person/{action}/{id}",
defaults: new { controller = "Person", action = "Index" }
);
routes.MapRoute(
name: "PersonID",
url: "Person/{id}",
defaults: new { controller = "Person", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Dashboard", action = "Index", id = UrlParameter.Optional }
);
Now if I remove those custom routes, and just run with the default route, the "mysite/person/list" view works just fine. But when I select a person, the URL ends up being "mysite/person/index/[id]" instead of "mysite/person/[id]". And if I manually remove "index" from that URL and make the path "mysite/person/[id]", a "resource cannot be found" message appears.
In that second route shown, I figured that giving the route a default action would route to the Index page and treat the ID in the URL as an ID, rather than as an action. With the current configuration shown above, if I navigate to the Person/List view I'm routed to the Person/Index view.
There are a few other actions associated with that controller (like JsonResults), which I'll need to handle as well.
What is the correct way to write the routes to support the URLs that I've indicated above? Also, can you recommend a resource that shows multiple examples of route-to-URL comparisons? Thanks for your help!
=== Edit 4/9/2015 at 10:21 AM ===
Based on the answer provided by #stephen-reindl, this is the solution that I implemented. Since we have multiple interfaces with a "Detail" view, I chose a default action of "Detail". This route recognizes a GUID.
// Support URL format of http://mysite/{controller}/{guid}
// Example: http://mysite/person/474f4357-39b2-45a2-b02b-6be04b2302fe
routes.MapRoute(
name: "DetailViewWithGuid",
url: "{controller}/{id}",
constraints: new { id = #"\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b" },
defaults: new { action = "Detail", id = UrlParameter.Optional }
);
You can add a constraint that a specific route is only taken into consideration if the constraint is fulfilled:
routes.MapRoute(
name: "PersonID",
url: "Person/{id}",
constraints: new { id = #"\d+" },
defaults: new { controller = "Person", action = "Index", id = UrlParameter.Optional }
);
In this case this route is only taken if id is a number.
Okay, I've got this case where I have two controllers:
HomeController
MathController
I want the routing for my HomeController to stay as default:{controller}/{action}/{id}. But I want to access the actions in the MathController with http://myurl/Task/Math/{action}.
So what I've done is to write my RouteConfig like this:
routes.MapRoute(
name: "Math",
url: "Task/{controller}/{action}",
defaults: new { controller = "Math", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Hem", id = UrlParameter.Optional }
);
When using the above configuration and manually entering the URLs in the browser both routing methods are working. Though when trying to add a "actionLink" it always uses the Task/{Controller}/{Action} route. Even if I'm creating a link for the Home controller like this: #Html.ActionLink("Hem", "Hem", "Home", null, new { #class = "navbar-brand" })
How do I configure either my routing or my action links so that I'll get the preferred functionality?
Routes match from top down in RouteConfig.cs. Your problem is that both route configs are "catch all" routes, which means both work for any controller/action. When you use #Html.ActionLink, MVC will render the url based on the 1st route it finds, which matches your "Task" path. There are few ways to change this to get what you want.
If you want to only use the "Task" path for the Math controller, then I'd change your route to this:
routes.MapRoute(
name: "Math",
url: "Task/Math/{action}",
defaults: new { controller = "Math", action = "Index" }
);
If you want to use several controllers for the "Task" path, then you can add a route constraint. You can use it like below and specify a list of controllers (regex), or you can create your own custom Route Constraint class and implement whatever functionality you want.
routes.MapRoute(
name: "Math",
url: "Task/{controller}/{action}",
defaults: new { controller = "Math", action = "Index" },
constraints: new { controller = "Math|OtherController" }
);
Or if you want to keep all controllers/actions matching both urls, then you have to flip your routes to get the default route to display first, or you can use #Html.RouteLink like so:
#Html.RouteLink("Hem", "Default", new { controller = "Home", action = "Hem" }, new { #class = "navbar-brand" })
I want customized routing based on Department Name and Product Name. for example /mobiles/nokia-6303
when i am calling products page it's working fine. when i am calling other than product page like Home page by default following controller and action method is executing
defaults: new { controller = "ContentPage", action = "ProductDetail" }
how to avoid this problem?
routes.MapRoute(
name: "ProductDetailsPage",
url: "/{DepartmentName}/{ProductName}",
defaults: new { controller = "ContentPage", action = "ProductDetail" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
Thanks in advance
Rajesh
Your routes are exactly the same. It's impossible to differentiate between /DepartmentName/ProductName and /Controller/Action. You need something else in the URL in order to differentiate between the two things, e.g.:
routes.MapRoute(
name: "ProductDetailsPage",
url: "/Products/{DepartmentName}/{ProductName}",
defaults: new { controller = "ContentPage", action = "ProductDetail" }
);
And then navigate to /products/departmentname/productname
Perhaps a slight modification to Ant P's excellent suggestion would be to place the text in between department name and product name?
routes.MapRoute(
name: "ProductDetailsPage",
url: "/{DepartmentName}/Products/{ProductName}",
defaults: new { controller = "ContentPage", action = "ProductDetail" }
);
Or to have details afterwards:
routes.MapRoute(
name: "ProductDetailsPage",
url: "/{DepartmentName}/{ProductName}/details",
defaults: new { controller = "ContentPage", action = "ProductDetail" }
);
Either of these URL approaches might get past your 'SEO team', since it is including soemwhat relevant information within the URL.
As other answers mention, the routing system can't differentiate between {controller}/{action} and {DepartmentName}/{ProductName}.
You can solve this problem by adding a constraint to a route. If a constraint isn't fulfilled, the route won't match the URL. You will probably need to create a custom implementation of IRouteConstraint. I see two options:
Create a constraint for the {controller}/{action} route, that will contain a list of possible names of controllers, that should be use the default URL pattern
Create a constraint for the {DepartmentName}/{ProductName} route, that will check the database (or some in-memory cache) whether department name and product name match some product
finally i have fixed this issue using routing config itself, please find the below code.
foreach (var d in departmentTranslation)
{
routes.MapRoute(
"ContentPage" + d.Name,
d.Name + "/{ProductName}",
new
{
controller = "ContentPage",
action = "ProductDetails",
id = d.DepartmentId,
ProductName = UrlParameter.Optional
});
}
I have issue in Routing in Mvc 4
My url goes like this
http://localhost:portnumber/Session/View?Id=918&Pid=186
I want my url to be like this
http://localhost:portnumber/Session/View/918/186
I have view like this
#Html.RouteLink("more..", "Default", new {Controller="Session",Action="View",Id=e.Id,Pid=e.Pid })
routes.MapRoute(
name: "SessionView",
url: "{controller}/{action}/{Id}/{Pid}",
defaults: new { controller = "Session", action = "view", Id = UrlParameter.Optional, Pid = UrlParameter.Optional }
);
The problem is that you're not referring to the correct route.
In the routing table, you've added a route with the name "SessionView", but in your #Html.RouteLink, you refer to a route called "Default".
The correct call should be:
#Html.RouteLink("more..", "SessionView", new {Controller="Session",Action="View",Id=e.Id,Pid=e.Pid })
Just try this
#Html.ActionLink("more..", "View", "Session", new {Id=e.Id,Pid=e.Pid })
Description:
Html.ActionLink(<<LinkText>>,
"<<ActionMethod>>",
"<<Controller Name>>",
new { Id=e.Id,Pid=e.Pid }, // <-- Route arguments.
)