I have three routes that look like that:
all.html
all/page-{numpage}.html
all/page-{numpage}-limit-{limit}.html.
First two work ok - which means that in my controller I'm getting the value of numpage or 1 if none is given:
public ViewResult All(int numpage = 1, int limit = 10) {}
numpage is whatever I typed in the address bar
Third route doesn't work at all - as if I went to the first route (all.html), so it's value is equal to 1, and limit is 10 - the defaults. However when I go to all/page-4.html?limit=3 I get correct values. What am I doing wrong? :D
One more thing - I create my routes dynamically, so code for registering them looks like that (rcache returns correct list of routes):
List<Tuple<Dictionary<string, string>, string, string, string>> routes = rcache.GetRoutes();
foreach (var route in routes) {
foreach (KeyValuePair<string, string> kvp in route.Item1) {
context.MapRoute(
route.Item4,
kvp.Value,
new { controller = route.Item2, action = route.Item3, id = UrlParameter.Optional, name = UrlParameter.Optional, numpage = UrlParameter.Optional, limit = UrlParameter.Optional }
);
}
}
ok well you are fighting with yourself. Why don't you put the last rule as first, and see what happens? Order of route rules makes a difference.
Just a quick note. Simplify your design and avoid complexity. What you are doing might work, but it's a terrible choice. Don't do it.
first of all you shouldnt allow anyone to add/edit/delete your routes. if someone doesnt really understand how it works, you are allowing them to break your application. i would definetely avoid it.
Well lets say you have to do it. then you need to validate the routes and rules as well, you cant just push it to your route table.
Also, lets say they add a route and it is not working, because your controller doesnt support it. you will take the blame. let them come to you with a request and then you add it to your route table.
You are the author of this code, no one else will be able to maintain what you wrote or what you were thinking while you were writing.
Related
My ecommerce application stores URL's for item pages in the database. There are thousands of these URL's, which are all root level (i.e. domain-name.com/{item-page-url}).
If I add all of these URL's to the route table by using a simple for loop to call RouteCollection.MapRoute for each URL site performance degrades exponentially. Why? The reason for this is here.
How should I properly handle this situation? Adding all of the routes to the route table doesn't seem right (not to mention the performance pretty much confirms that). I've seen a few ideas about inspecting all incoming URL's and then trying to match that to the URL's in the database but don't fully understand how I'd implement that, nor am I sure if it's the best approach.
Any ideas or suggestions? This seems like it would be not so uncommon, but I haven't found a concrete way to handle it.
If you can change your route to
mycreativeshop.com/product/my-product-name then adding following route to the top of your route config file can help you.
routes.MapRoute(
"CustomRouteProduct",
"product/{id}",
new { controller = "yourcontrollername", action = "Index" }
);
and in the action map the parameter value with name of your product name
public ActionResult Index(string id)
{
//var prdName = id.Replace("-", " ");
//look up prdName in database
return View();
}
Update
Added following as a top route
routes.MapRoute(
"CustomRouteProductZX",
"{id}",
new { controller = "Content", action = "Index" }
);
and by accessing http://localhost:12025/Car-Paint I was directed to Index action of ContentController where I accessed "Car-Paint" in parameter id
But, above having above blocks patterns like http://localhost:12025/Home/ (here Home is also treated as a product)
I've got a website which has a URL structure that is not at all useful for breadcrumbs, conducive to SEO, or intuitive for users. It's something like
asdf.com/directory/listing/{unique_id}/{unique-page-name}/
I would really like to change this to
asdf.com/{state}/{city}/{unique_id}/{unique-page-name}/
or something very similar. This way, I can implement breadcrumbs in the form of
Home > State > City > Company
Does anyone have any ideas as far as converting the current structure to one as I've described above? Any way I look at it, it seems that it'll require a complete overhaul of the website. It would just be great to be able to show users something like Home > Florida > Miami > Bob's Haircuts
Thanks!
You'd just need to be creative with your routes: http://ellislab.com/codeigniter/user-guide/general/routing.html
You can set up a route to catch all traffic and point it to directory/listing, then in your listing method - you can access the url segments manually. For example:
// application/config/routes.php
$route[':any'] = "directory/listing";
/**
you might have to play with this a bit,
I'm not sure, but you might need to do something like:
$route[':any'] = "directory/listing";
$route[':any/:any'] = "directory/listing";
$route[':any/:any/:any'] = "directory/listing";
$route[':any/:any/:any/:any'] = "directory/listing";
*/
// application/controllers/directory.php
function listing()
{
// docs: http://ellislab.com/codeigniter/user-guide/libraries/uri.html
$state = $this->uri->segment(1);
$city = $this->uri->segment(2);
$unique_id = $this->uri->segment(3);
$unique_page_name = $this->uri->segment(4);
// then use these as needed
}
OR, as is probably the case, you need to be able to call other controllers and methods -
You can change the URL to point to a controller, then do the listing stuff -
So your url would become:
asdf.com/directory/{state}/{city}/{unique_id}/{unique-page-name}/
and your route would become:
$route['directory/:any'] = "directory/listing";
Then, you'd need to update the uri segments in your listing method to match the 2nd, 3rd, 4th, and 5th segments.
This way, you could still call another controller and it wouldn't be caught by your custom route:
asdf.com/contact/ --> would still access the contact controller and index method
UPDATE
You could also get creative and use a regular expression to catch any urls with state names in the first uri segment - then push those to directory/listing and then all other controllers will still work and you don't have to add the directory controller in the url. Something like this might work:
// application/config/routes.php
$route['REGEX-OF-STATE-NAMES'] = "directory/listing";
$route['REGEX-OF-STATE-NAMES/:any'] = "directory/listing"; // if needed
$route['REGEX-OF-STATE-NAMES/:any/:any'] = "directory/listing"; // if needed
$route['REGEX-OF-STATE-NAMES/:any/:any/:any'] = "directory/listing"; // if needed
/**
REGEX-OF-STATE-NAMES -- here's one of state abbreviations:
http://regexlib.com/REDetails.aspx?regexp_id=471
*/
I'm working on a project to rewrite an aspx site as MVC3. I want to make the old URLs work on the new site. I have named my controllers and actions such that the URLs actually contain enough info in the query string to route correctly but I'm having trouble getting the routing to work since it doesn't like the ? in the URL.
Basically I have old URLs like this:
www.example.com/Something/SomethingElse/MyPage.aspx?Section=DetailSection&TaskId=abcdef
I tried to create a route using:
routes.MapRoute(
"OldSite",
"Something/SomethingElse/MyPage.aspx?Section={action}Section&Id={id}",
new { controller = "Task", action = "Index", id = UrlParameter.Optional }
);
I want it to route to the correct new URL which is:
www.example.com/Task/Detail/abcdef
I know that all traffic to the MyPage.aspx page should go to my new Task controller and the beginning of the Section parameter always matches one of a few corresponding actions on that controller.
Unfortunately I have found that I get an error that a route can't contain a question marks. How should I handle this? Would it be better to use URL rewriting? Because this is a private site I'm not concerned with returning permanent redirects or anything - no search engine will have links to the site anyway. I just want to make sure that customers that have a URL in an old email will get to the right page in the new site.
In this one case I think the simplest way would be to have your old page mapped to a route:
routes.MapRoute(
"MyPage",
"Something/SomethingElse/MyPage.aspx",
new { controller = "Task", action = "MyPageHandler" }
);
And have this route mapped to an action method in TaskController:
public ActionResult MyPageHandler(string section, string taskId)
{
if (section.Contains("Detail"))
{
// execute section
}
}
This way you're treating your old site's query string for what it is: a query string. Passing those parameters straight into an action method is the most MVC-y way to interpret your old site.
I have two routes that are satisfying two different urls. how can i remove ambiguity?
Depending on which is first in the list is which is being picked up.
downloadFile and isEdit as both nullable bool.
context.MapRoute("Asset_GetImage", "Admin/{controller}/{action}/{assetId}/{downloadFile}");
context.MapRoute("News_Read", "Admin/{controller}/{action}/{newsId}/{isEdit}");
thanks
You don't need separate routes at all; you are collecting the exact same data types in each.
Just change assetId and newsId both to simply id and code your controllers accordingly. The controller name is already in the URL.
you could make the routes more specific.
For example, specify the {controller} for each of these:
context.MapRoute("Asset_GetImage", "Admin/Asset/{action}/{assetId}/{downloadFile}");
context.MapRoute("News_Read", "Admin/News/{action}/{newsId}/{isEdit}");
you just need to make sure the controller default is added.
as an example from one of my apps:
routes.MapRoute(
"Calendar",
"Account/Calendar/{Year}/{Month}",
new { controller = "Account", action = "Calendar", Year = DateTime.Now.Year, Month = DateTime.Now.Month }
);
{controller} and {action} aren't in the route but the defaults are still set so it knows what to do with it
I am trying to create a route that can allow for different formats (html/json/xml etc)
This is what I am trying, but it doesn't work.
routes.MapRoute(
"Default",
"{controller}/{action}/{id}/{format}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional, format = "html" },
new { format = #"html|json" , id=#"\d+"}
);
The routes that do work are these:
/Person/details/1
/Person/details/1/json
But this don't work:
/Person which imo should default to /Person/Index/html
/Person/json and imo should lead to /Person/Index/json
But it doesn't match.
For the second of the ones that don't work I assume it thinks json is an action and that's the problem there, but for the first one I don't fully get it as I have defaults for each part of the url, and id is optional and it can't think html/json is the id as I say id have to be a number anyway, so it should imo get that one.
So who aren't the first one working?
For the second one I have been meaning to write a regex like this (I know it's not a real regex btw, any help on that is also appreciated..): action = #"!(html|json|\d+)" so that it will see that I'm not trying to say that json/html is an action, but that it then should use the default action of index.
But since the first one isn't even working I think I have to resolve that one first.
The problem
Routes can have multiple optional parameters (although I suggest you don't use this unless you know Asp.net MVC routing very well), but you can't have non-optional parameters after optional ones as you've done it...
Imagine what would happen if you set a non-default "json" value for your format but don't provide id? What would come in place of the id? You'd run against a very similar problem with multiple optionals, hence I advise you not to use them.
Two solutions
Change parameter order:
"{controller}/{action}/{format}/{id}"
Use two routes
routes.MapRoute(
"Ordering",
"{controller}/{action}/{format}",
new { controller = "Home", action = "Index", format = "html" },
new { format = #"html|json|xml"}
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}/{format}",
new { controller = "Home", action = "Index", format = "html" },
new { format = #"html|json|xml", id = #"\d+"}
);
The first one will cover requests where ID is optional and you do provide format, and the second one will cover situations when ID is present.
The id parameter cannot be optional. Only the last parameter of a route definition can be optional.