here is my navigation hierarchy.
Catalog
-Collection - Media - Attributes - User
Collection
-Media - Products - Attributes
I have controller for all. This is what my url should look like
http://Localhost/Catalog/Collection/1 // return all collection for catalogeid 1
http://Localhost/Catalog/Media/1 // return all media for catalogeid 1
http://Localhost/Collection/Media/1 // return all media for collectionid 1
Now with default route
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
It looks for action”Collection” in my “Catalog” Controller ,as I have already define “List” method in “Collection” Controller, I don’t want to redefine same in my “Collection”
Then I tried this
routes.MapRoute(
"Catalog_Collection_List", // Route name
"Catalog/Collection/{id}", // URL with parameters
new { controller = "Collection", action = "List", id = UrlParameter.Optional } // Parameter defaults
);
But result is the same.
Another problem is how to generating link as I mentioned above.
I cant use
#Html.ActionLink("Collection","Collection", "List", new { id = 1 })
As this generates link like
Localhost/Collection/List/1 //I don’t want
My ultimate goal is that all the action related to “Collection” should go under “Collection” controller.
i dont know what i am missing.
hope my question is clear.
thanks for any help.
EDIT
making my question more clear. take a look this sample url
localhost/Catalog/Media/1 // which gives media for catalog
localhost/Collection/Media/1 // which gives media for collection.
now as per conventional way i have to define "Media" action in each controller. which i dont want. what i want is based on URL i want to invoke "List" action from "Media" controller.
i hope this is pretty clear.
Im having a bit of a hard time following the problem here. You dont want the url above /collection/list but that is what you specified in your action link. Looking at your URLs you have a consistency problem to start.
"It looks for action”Collection” in my “Catalog” table ,as I have already define method “List” method in “Collection” table, I don’t want to redefine same in my “Collection” Then I tried this" by table I think you mean controller here right?
So you should stick to the format in general Url = /Controller/Action/id
Collection/List/1.
You can absolutely map it somewhere else (and the order is surely important - the first match in your routing table wins)- but ask yourself if you want to deviate from the standard so far.
EDIT
I believe you want this route, add it BEFORE your other routes.
routes.MapRoute(
"Catalog_Collection_List", // Route name
"Catalog/Media/{id}", // URL with parameters
new { controller = "Collection", action = "List", id = UrlParameter.Optional } // Parameter defaults
);
Related
How can I route requests to a default PageController for routes that do not map to a controller or action? But for routes that do match a controller or action, have those behave as normal, using ASP.NET MVC?
Basically I have a CMS backend that I have developed and I need to be able to inspect the route, to see if it matches a route for a page, stored in the database and if so, forward the request to the default PageController, which handles loading the pages content from the database. There are also CORE pages, that do have their own Controllers and Actions defined, and if you enter a route that doesn't match a pages route in the database, I need it to revert to the default behavior of ASP.NET MVC and look for the {controller}/{action}.
I have searched and searched online, with not much luck finding how I could do this. Any help would be greatly appreciated.
Set your routes up so the ones for existing controllers and actions are first, then have a catchall that maps to your PageController:
// More specific routes go here
routes.MapRoute(
null,
"{controller}/{action}/{id}", // URL with parameters
new { action = "Index", id = UrlParameter.Optional }, // Don't put a default for controller here
// You need to constrain this rule to all of your controllers, so replace "ControllerA" with an actual controller name, etc
new { controller = "ControllerA|ControllerB|ControllerC" }
);
routes.MapRoute(
null,
"{*path}",
new { controller = "Page", action = "Index" }
);
Anything that isn't matched by the first rule and any rules you put before it will fall back to your page controller, with the path in a path parameter on your index action method.
Now, the question. I have an eCommerce website and I have a controller called Store with an action Index. When someone types www.mysite.com/sony, I want to route to controller Store and action Index with parameter brand=Sony. If someone type www.mysite.com/sony-tv, I want to route to controller Store and action Index but with the parameters brand=sony and department=tv.
I obtained that by creating a route for every situation storing in a database, and building the routes dynamically when the app starts. Its works fine in a few cases.
First, i need to index the routes. I need to map the route sony-tv before the sony, otherwise the /sony-tv maps to /sony equally.
When i enter at site's home (www.mysite.com) and click at Url.Action("Index","Store", new {brand=Sony}) it route me to www.mysite.com/sony. NICE!. Now, inside the SONY brand i'll click at Url.Action("Index","Store", new {brand=sony, department=tv}) and I can see all TV's from Sony.
Everything is running fine until here. In the database, I have 1 route to /sony where I say i have a parameter named brand with value Sony and a constrained named brand with value Sony. I have another route saying the same way to sony-tv. The pattern sony-tv has a parameter named brand with value sony and a parameter named deparment with value tv, and the sames constraints of parameters.
In my head, its means that the route for www.mysite.com/Sony is Store/Index/brand=sony and the www.mysite.com/sony-tv is Store/Index/brand=sony&department=tv. With the constraints, i understand that if department is not TV or if the parameter department does not exists, it will send to www.mysite.com/sony
When i'm at www.mysite.com/sony-tv, if I pass my mouse over the other brands, the link build to Url.Action("Index","Store", new {brand=Apple}) is www.mysite.com/Apple-Tv
I have a route to Apple-TV equal to Sony. The URL exists but i'm not passing the TV parameter. I passed on this link (brands links) only the brand. I want to move the user to brand's root he's moved to brands + department.
I don't know, its looks like the department variable is passing through again and I don't know how to cancel that.
I'm completely wrong? What i'm doing is valid? I can do that? Where is my mistake?
At cshtml file:
#Html.ActionLink(febrand.Name.ToUpper(), "Index", new { controller = "Store", brand= febrand.FriendlyName, department = string.Empty })
at final html file (show source code from google chrome):
SONY
Fisrt, that seems like a lot of work for something that you could do with two custom routes. Additionally, as your route table gets larger (eg. adding more brands and/or departments), each request to your site will take longer to fulfill due to having to scan a larger list of routes.
So, lets attempt to fix your route table. Place these two routes above your default route in the global.asax:
routes.MapRoute(
"Department",
"{brand}-{department}",
new { controller = "Store", action = "Index" };
routes.MapRoute(
"Brand",
"{brand}",
new { controller = "Store", action = "Index" });
As for your issue, when you create your action link, the routing engine is holding onto the department route value from the view you are currently on. To make it forget that parameter when generating a link, send a null across for the department variable when you do not need it.
#Html.ActionLink("Apple", "Index", new{controller="Store", brand="Apple", department = string.empty});
EDIT
I feel you may be in a weird edge case with your routing (and there are numerous examples of this problem all across SO, such as here and here). The solution, other than the one I provided, is to switch to Html.RouteLink instead of Html.ActionLink.
RouteLink Signature that we are going to use
Html.RouteLink(string linkText, string routeName, object RouteValues)
Example Brand link for your code
#Html.RouteLink(febrand.Name.ToUpper(), "Brand", new { controller = "Store", action = "Index", brand= febrand.FriendlyName})
I code lots of ASP.NET but I'm kind of new with .net MVC, I've a default route registered like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
And I want to add another Administrator area on the site and all the URL would be something like "http://localhost/Administrator/controller1", "http://localhost/Administrator/controller2", etc. I've lot of controllers in the Administrator namespace and I'm trying to register those controller with only one MapRoute, I did something like this:
routes.MapRoute("Administrator_default", "Administrator/{controller}/{action}/{id}", new { controller = "Administrator", action = "Index", id = "" });
it works with those controller but one problem is that in some other controller while I try to do a redirect like:
return RedirectToAction("Index", "Forum");
Then I'll always be redirect to http://localhost/Administrator/Forum instead of http://localhost/Forum, it's not a big issue but make the URL looks strange, I tried to restrict to certain namespace but it's not working. It looks just as I'm trying to register two default route and .Net just match the first one, I'm wondering is there a way to make it two default route and map on only specific path only?
This exact issue is why Areas were added to MVC 2. http://www.asp.net/whitepapers/what-is-new-in-aspnet-mvc#_TOC3_2
Agree with Zach's answer.
Not ideal, but you do have the option to have controllers in the controller root folder (e.g. /controllers/HomeController.cs) of your project as well as the controllers in Areas (maybe high level root pages that display menus for areas).
Secondly a quick tip on using the RedirectToAction method. You can specify the area you would like to redirect too using the route parameters e.g:
RedirectToAction("Index","Form", new { area = "MyOtherArea" });
I'm trying to wrap my mind around the way ASP.NET MVC implements routing.
From what is my current understanding, it seems my route string much have a "{controller}" and "{action}", otherwise it doesn't work?
How would I define the route that using a SearchController and Search action taking both SearchKeywords and SearchCaseSensitive arguments had the following URL?
domain/SearchKeywords/CaseSensitive
Even simpler, how do I map domain to controller SearchController and to Search?
From what is my current understanding,
it seems my route string much have a
"{controller}" and "{action}",
otherwise it doesn't work?
Values for the controller and action tokens are required. You have 2 options for providing the values:
1) Using {controller} and {action} tokens on the URL template. e.g.:
routes.MapRoute(null, "{controller}/{action}");
2) Using default values for controller and action. e.g.:
routes.MapRoute(null, "some-url",
new { controller = "Search", action = "Search" }
);
How would I define the route that
using a SearchController and Search
action taking both SearchKeywords and
SearchCaseSensitive arguments had the
following URL?
domain/SearchKeywords/CaseSensitive
The URL host (or domain) is not considered by the routing system, only the application relative path. You can do this:
routes.MapRoute(null, "{SearchKeywords}/{CaseSensitive}",
new { controller = "Search", action = "Search" }
);
You can also provide defaults for SearchKeywords and CaseSensitive, if you want to make either of them optional.
You can add controller = "Search", action = "Search" to the defaults (the last parameter).
The routing engine will use values in defaults to fill in for parameters that aren't in the URL.
If you want to have a 'domain' parameter in your route, you must put this at the top of the route registration. The 'domain' parameter in the second anonymous object is a constraint and here is set to be a regular expression that tests to see if the domain is either of the possible domains "DefaultDomain" or "OtherDomain".
routes.MapRoute("DomainRoute", "{domain}/{controller}/{action}",
new {domain = "DefaultDomain", controller = "Search", action = "Search"},
new {domain = "DefaultDomain|OtherDomain"});
I am looking to produce an MVC site which has complete control of the url structure using routing.
routes.MapRoute(
"BlogView", // Route name
"view/{blogurl}", // URL with parameters
new { controller = "view", action = "view", productLink = ""} // Parameter defaults
);
routes.MapRoute(
"ProductGrid", // Route name
"category/{category}", // URL with parameters
new { controller = "category", action = "Index", category = "" } // Parameter defaults
);
I currently have the follwoing urls;
www.myblog.com/view/first-post
www.myblog.com/view/another-post
www.myblog.com/category/code
www.myblog.com/category/example
The first two urls relate to the detail view, the latter two relating ot a category view.
I have a database with the following structure; I ensure that the url (chrUrl) is a unique key.
url ( idurl (int),
chrURL,
chrAction,
chrController
)
My plan is that it is possible to look up rewrite the route lookup table so that the follwoing urls redirect to the correct view and page in the site;
www.myblog.com/first-post
www.myblog.com/another-post
www.myblog.com/code
www.myblog.com/example
Is this possible? Perofmance aside, is there a problem with this and how shoudl I go about this?
Since you don't have anything to differentiate between view and category items, I'd think about using a default controller which checks if the id is in the categories table and passes control to either the View or the Category controller.
routes.MapRoute(
"Root", // Route name
"/{id}", // URL with parameters
new { controller = "default", action = "redirect"} // Parameter defaults
);
But if you can live with having "/category/" in your category urls, that will be the more elegant solution on the back end.
First up, I would suggest coming up with a URL scheme that you are happy with. (seems you have one already)
Then I would use a ControllerFactory that will be responsible of Instantiating and
running the right action on the right controller. That is independent of any routes that you define in your route table - in fact it wont matter what you have there since you want your URL to be "database driven". You invoke the controller factory from your Global.asax file :
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new Controllers.ControllerFactory());
}
Then in the GetControllerType method in your ControllerFactory, you inspect the URL with
RequestContext.RouteData.Values.ContainsKey("keyname")
to work out the url scheme the user is presenting, and do a database look-up based on that.
If you want to take this one step further, your database can also contain references to the controller to instantiate, but that would be an overkill in your situation. As a quicknote, we use that in a solution where it was important to provide the ability for non-developers to create templates without involving dev - the database held url schemes, controller and views to render on that controller.
While you are at it, if you want to make things more elegant, create a BaseController that your controllers inherit from, and in there set things in your ViewData such as your SEO tags (MetaDescription, Title, etc) - look these up from your database.