Am building a CMS using MVC4. My experience with MVC is limited and trying to create a MapRoute that can handle the page structured created by the CMS. URLs for the pages would be along the lines of website.com/About
To handle this I have come up with the following
routes.MapRoute(
name: "Default",
url: "{p}",
defaults: new { controller = "Home", action = "Index", p = UrlParameter.Optional }
);
This works fine for root level pages but if I want sub pages like website.com/About/OurTeam
I get a 404. Ideally what I would like is just be able pass either the whole url after the .com bit as a string and sort it out in the controller or to split the levels up as an array of parameters and pass that through as 'p'.
Hope that makes sense. Any ideas?
You can use:
routes.MapRoute(
name: "Default",
url: "{*p}",
defaults: new { controller = "Home", action = "Index", p = UrlParameter.Optional }
);
The asterisk indicates that it's a catch-all route. Keep in mind that these routes are extremely greedy, make sure that this stays below any specific routes.
You could also add a route constraint to this route which can determine whether the page exists in the database or something. See this post for more info.
Related
I asked a previous question here, in which I attempted to use a blank URL to catch a default page.
After some more digging, and some trial and error, I stumbled upon the use of {*url} to catch the root URL. I also attempted to use a constraint to manage the "tidy" url that I want to use. My RouteConfig now looks like so:
routes.MapRoute(
name: "LoginRoute",
url: "{login}",
defaults: new { controller = "LoginController", action = "Index", id = UrlParameter.Optional },
constraints: new { login = "login" }
);
routes.MapRoute(
name: "Default",
url: "{*url}",
defaults: new { controller = "authController", action = "routingsuccess" }
);
However, neither of these routes result in a web page. Instead, they still result in 404. Curiously, however, Phil Haack's RouteDebugger reports that the URL I am using is valid, as demonstrated here:
To clarify, accessing the root url (in this case, localhost:3000) results in the same issue.
There is a valid controller, and a valid view behind it with the appropriate action. What could possibly be wrong?
You can just use the normal default routing.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "authController", action = "Index", id = UrlParameter.Optional }
);
This just mean, if a controller isn't passed in the url then it will use MainController. If an action isn't passed then it will use Index. This mean http://website.com will go to MainController action Index.
Maybe you are using [Authorise] attribute, or something else for authentication.
I will just make a guess : -
Your route is registred, and there is no problem in it. Problem occurs when you try to access it. There might be some kind of authorisation, like an [Authorise] attribute, that would block non access users to get to your route.
Or there might be something else, that would be causing your code to not be able to reach the ActionResult.
To confirm this, put a breakpoint in the constructor of the COntroller.Remove all attributes from the COntroller. If your debugger stops at the breakpoint in constructor, then the issue is not is registering the route, but access related.
Let me know if it helps.
i have url called http://0.00.000.000:0000/ics/Account/Login but i want to show the fixed url like "http:abc.com" in all pages. what ever it may the action and view i require fixed url for my app. can we use files in mvc or routing to achieve this?
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I built an web application where the RouteConfig.cs was the default one.
Now I received a task where I need to append a customer tracking ID in the beginning of the URL but keeping the same functionality it has when it is not present too.
http://localhost:60202/Home/Index //Generic customer
http://localhost:60202/Location/123/Home/Index //URL with the customer tracking id
This code 123 is a tracking ID where my customer knows the location he originates the call to my page. I have no power to ask them to change this since they use across the globe.
I tried to achieve this with this custom route:
routes.MapRoute(
name: "Route",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "Location/{trackingId}/{controller}/{action}",
defaults: new { trackingId = 0, controller = "Home", action = "Index" }
);
In this case I can access my application with both URL schema I provided above but I couldn't manage to make ActionLink and BeginForm take this into account.
#Html.ActionLink("InĂcio", "Index", "Home") //this should have full URL info
Is there a way to achieve this without the need to change every ActionLink, Url.Content and BeginForm and surround them with if in every case?
How could I use both URL schema without change every navigation code?
Our currently implemented approach is to duplicated the folders in IIS since there is only 4 as of today but in near future it can be a pain to maintain.
I don't know why but based on this question it should work out of the box.
Edit 1
Looks like changing position of these two MapRoute are making the ActionLink work as I expected. Unfortunately Url.Content still is buggy.
Well, it's embarrassing but looks like the order you add routes make difference. So I changed to this:
routes.MapRoute(
name: "Default",
url: "Location/{trackingId}/{controller}/{action}",
defaults: new { trackingId = 0, controller = "Home", action = "Index" }
);
routes.MapRoute(
name: "Route",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
With this change every ActionLink started to work as I expected. I still had the problem with Url.Content I was using in Ajax calls.
In this case I figured out that I should use Ulr.Action for this instead.
Referenced js and css still used the second MapRoute (or don't even care about the route at all) but this is not a problem.
I'm a bit baffled by how MVC is figuring out my routing details. Let me see if I can explain this right.
So ... given that I have the default route ...
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "CMS", action = "GetPage", id = UrlParameter.Optional }
);
And my app is a content management system so I want to create nice urls from the site structure so i'll map a wildcard url that lets me determine if i need to render a 404 based on what's in my database ...
routes.MapRoute(
"CMS",
"{*path}",
new { controller = "CMS", action = "GetPage", path = string.Empty }
);
Herein lies the problem.
MVC will basically match everything to the default route because technically no params are required assuming "GetPage" on the "CMS" controller requires no params, which is not what i want.
What i'm trying to say to it is something like "given 2 or 3 url parts, look for a controller and action match with an optional id parameter but for all other urls including ones that you can't match to this route fall down in to the CMS route".
The only "easy" way I found to do this is to change the first route to something like this ...
routes.MapRoute(
"Default",
"Get/{controller}/{action}/{id}",
new { controller = "CMS", action = "GetPage", id = UrlParameter.Optional }
);
Then any url that starts "Get/" will match that route and all other routes automatically fall down in to the second route, but that doesn't sit right somewhere in my head and I can't figure out quite why yet (i think it's because it doesn't really solve the problem it simply moves it).
My problem is that I don't really want a route that says "given no values match this route anyway" so I changed it to this ...
routes.MapRoute(
"Default",
"{controller}/{action}/{id}"
);
Now for some odd reason literally every request is hitting the catch all (not quite what i want but close).
So any ideas guys?
EDIT:
I came a touch closer with this ...
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { id = UrlParameter.Optional}
);
... but that now matches all urls with 2 parts "foo/bar" rather than dropping through like it should to the other route because there is no "foo" controller.
Ok I have a solution, it works for me because 99% of requests need to map to the CMS route but in your case it may not if you have a lot of controllers you need to map to.
I was hoping to find an ideal solution for all but this is merely an ideal in my scenario ...
So assuming you have (like me) only a cms controller and a an accounts controller you can do this:
routes.MapRoute("Account", "Account/{action}", new { controller = "Account" });
routes.MapRoute(
"Default",
"{*path}",
new { controller = "CMS", action = "GetPage", path = string.Empty }
);
That way only urls starting with "Account" get caught by the first rule, and everything else falls through to the default route and gets handled by the cms controller.
I plan to simply add more routes as I add more controllers. It's not an ideal solution because it could mean i end up with a lot of route mappings in the long term but its a good enough solution to meet my needs.
Hope it helps someone else out there.
Maybe I don't understand your problem fully but why not have this route:
routes.MapRoute(
"CMS",
"CMS/{action}/{path}",
new { action = "GetPage", path = string.Empty }
);
and add it into the route collection before your default path...
I'm attempting to do a custom route so I can prefix a url in my application with a chosen string and the do some processing based on that. The problem I'm running into is, that the action links that are generated are not contextualized based on the url that it exists on.
Routes:
routes.MapRoute(
"TestRoute",
"TEST/{controller}/{action}/{id}",
new { controller = "Space", action = "Index", id = UrlParameter.Optional });
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Space", action = "Index", id = UrlParameter.Optional });
Navigating to TEST/Space/Index works, as well as Space/Index, but the odd issue I need fixed is that the links generated via ActionLink do not obey the context in which they are loaded, at least for the {controller}/{action}/{id} default route. Pages that are loaded under TEST/Space/Index list links properly, but when /Space/Index is loaded, they are all referencing the TEST/ route that the calling url does not. Is this the default behavior? Is there a way to get these links to generate in the proper context?
Edit:
The first place I saw this was in the Html.BeginForm without the TEST/
Html.BeginForm("ToTheMoon", "Space", FormMethod.Post)
which renders the link as TEST/Space/ToTheMoon
but it also shows up in links:
#Html.ActionLink("Take Me To The Space Port", "SpacePort", "Space")
which renders TEST/Space/SpacePort
I found a bit of a way around this so that the context wouldn't be lost. Here's what I did to get this to work.
TestRoute changes to this:
routes.MapRoute(
"TestRoute",
"{path}/{controller}/{action}/{id}",
new { controller = "Space", action = "Index", id = UrlParameter.Optional },
new { path = #"TEST" },
new string[] { "The.Namespace" });
Setting the constraint on path and removing it from the route makes this routing work. Now I can hit the /TEST/Space/Index and all my links generated from ActionLink behave as intended. Also on a related issue, I ended up adding the namespace specification in the map route, as the development environment required that be in there to properly route things to the TEST path.
Some of the info I found was on this page.
If you do:
#Html.ActionLink("Text", "Index", "Space")
That is going to match the first route in your collection (TestRoute). This is the default behavior.
If you want to choose a specific route then use #Html.RouteLink instead.
If you want to target a specific route, you could use RouteLink extension, it allows you to specify which exact route should be used to generate the link.
#Html.RouteLink("with Test", "TestRoute")
#Html.RouteLink("with Test", "TestRoute", new {controller="Space", action="Foo"})
#Html.RouteLink("without Test", "Default", new {controller="Space", action="Foo"})