MVC3 Routing strange behavior - c#

I found something strange with routing...
I´m testing a MVC3 application in Visual Studio Web Express 2012
I created a new MVC3 application to isolate the problem
I added the following route before the default route:
routes.MapRoute(
"default_localization",
"{language}/{country}/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Then without any other change (there are no areas anything just the initial files after creating the project), I ran the application and at first sight everything was working fine. Since it is a new application there are two links at the top of the page:
Home
About
The action links look like:
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.ActionLink("About", "About", "Home")</li>
Then this is what is happening:
When the browser URL is: http://localhost:54870/
The Home link is: http://localhost:54870/
The About link is: http://localhost:54870/Home/About
HTML
<li>Home</li>
<li>About</li>
Which is OK
But after clicking the About link, the browser URL is: http://localhost:54870/Home/About
The Home link becomes: http://localhost:54870/Home/About
The about link becomes: http://localhost:54870/Home/About/Home/About
They still execute the correct action even when the link is messed up.
HTML
<li>Home</li>
<li>About</li>
If I remove my custom routing everything works as expected
Why is this happening?
How can I fix it?

I just found the problem
Basically I read several routing articles and finally I got it, my problem was that my custom route was been picked up always after I clicked the About link
Why?
Let's consider it:
When my URL was http://localhost:54870/, my custom route was not picked up because I didn't have default values for {language} and {country} therefore my route didn't match
But when my URL was http://localhost:54870/Home/About my custom route was always picked up because the route engine assumed that Home/About were the {language} and {country} segments and since I had default values for {controller} and {action} the rout simply was a match
Well I learnt my lesson and I learnt more about routing. In the future I'm planning to follow the KISS principle when defining routes

Try replacing your route with something like this:
routes.MapRoute(
"default_localization",
"{language}/{country}/{controller}/{action}/{id}",
new { language = "en", country = "US", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
See if that works.
Hope this is of help to you.

Related

MVC 4 - issue with routing to non-area controllers

I have a project that I am upgrading from MVC 2 -> MVC 4. During the transition from MVC 2 -> MVC 3, I noticed that some of my hyperlinks broke and were no longer matching the routes as defined before. I have the following project structure:
...
App_Data
Areas
Test
Controllers
TestController
Views
Models
Controllers
PartialController
Views
Scripts
...
The links that are generated are in the format /Test/Partial/Render. If I go back and run the project before the migration, the PartialController Render action is hit as expected. However, now the app says that it can't find an action because there is no Test/Partial controller. I actually am not sure how it worked before, but can't seem to get it to map correctly.
Is there something I'm missing? Here is the relevant code:
Global.asax.cs:
...
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
...
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = "" }
);
TestAreaRegistration.cs:
context.MapRoute(
"Test_default",
"Test/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
I did move the Controllers folder up a level to be more in-line with how the project should be structured; beforehand it was in the Areas folder itself. However, none of this worked before I moved that, so I doubt that is the case. I also thought that Autofac had something to do with this, but I am less certain of that because if I shave the "Test" portion out of the URL it matches as expected.
I guess this all boils down to a question on how to check in a "generic" controllers directory first, before matching to an area-specific controller directory, even with an area specified in the URL.
Thanks in advance for your help!
EDIT: If it helps, I noticed that in the existing MVC 2 solution, if I go to Test/Home for example, it will invoke the Index method of the HomeController. However, this does not happen in the new solution. Is this because there is no View associated with the new routes? I have not made new .cshtml files for each of the corresponding .ascx files yet, but I didn't think that should matter much as they are used otherwise.
So apparently the issue was related to namespaces. I had seen that answer on questions like this, but those had to do with collisions finding views. Here is the line I ended up adding to each of my Area registrations:
context.MapRoute(
"Test_default",
"Test/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new string[] { "Project.Web.Controllers", "Project.Web.Areas.Test.Controllers" } //added this line
);

How to make an URL in a MVC page independt of a '/id' is present or not

I have a MVC application which is used by an administrator and some users. The users can see a list of their own tools on a page, with a URL:
/Tool/List
The administrator can see all the users lists pages with a URL like:
/Tool/List/1234
Where 1234 is the id of the user.
In order to download a list of the tools in an Excel-file the page has the following:
<a onclick='window.open("../ExcelListe");'>Download</a>
Which works fine when you are the administrator. But when you are a user (without the '/id' in the URL) the HTML must be:
<a onclick='window.open("ExcelListe");'>..</a>// without ../
I can solve the problem by making a test on the URL in the filterContext and making some if-else in the razor code. But is there a smarter way to solve this problem?
I have only registered the default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
In MVC it is better to never use fixed or hardcoded links, it is always better to use a helper, in this case Url.Action().
The link to ExcelListe looks to be at the same level as List, so I'll assume that ExcelListe is also an action method of the ToolController.
Put this in your View (e.g. List.cshtml):
#{
var link = Url.Action("ExcelListe");
}
<a onclick='window.open("#(link)");'>Download</a>
You can tweak the parameters of Url.Action() to get the URL that you need.

How to handle a virtual path created by proxy server in MVC route?

I am fairly new to MVC. Recently I developed a site and hosted it behind a proxy server. I access my site using internalhostname/site/{controller}/{action}/{id} for test, which works fine.
However, when my users are connecting the site, they would use an external url like this: externalhostname/apps/site/{controller}/{action}/{id}. Now when my views attempt to initiate a call to the controller according to the default route config, the URLs being generated become externalhostname/site/{controller}/{action}/{id}, notice "/apps" is gone.
Well, this is a known problem to me. Because when creating the URL, host name does not include "/apps". In other sites created in regular ASP.NET page, I would simply hijack the URL creation and replace host with host/apps, that can fix the issue. But I don't know how to do this in MVC world.
Also I am using Telerik controls (for MVC) that also initiate requests by controller and action, which lead to the wrong URL eventually.
The route config is default. I did try to change the rule but all of those only affect the url format after . Nothing could allow me to change the behavior ahead of it.
I have been struggling for days and couldn't see a way out. Appreciate for some advice. Thank you.
I cannot change the proxy rule. That is not an option to me.
Environment: MVC 4, IIS 7.0, if these matter.
Try to add new entry in your route config.
routes.MapRoute(
"Default2", // Route name
"apps/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults,
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Take note of the order.

MVC Areas and routing issue

I'm having some issues getting Areas working correctly within MVC 3. I have the following folder structure and an Admin area set up:
I'm trying to navigate from the admin page (Index) to the the other view pages in the Admin area for example Admin/Floor/Create etc... but I get The resource cannot be found error on every url combination i've tried for example:
#Html.ActionLink("floors", "Index", "Floor", new { area = "Admin" }, null)
/Floor/Index/
/Admin/Floor/Index/
None of which work. I managed to use the first ActionLink one to link to the admin index page from outside of the area but it's no use here.
The area registration looks like this:
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
Can anyone offer some help?
Thankyou
The problem is with your routing. You need to set the default controller to be AdminController:
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { controller = "Admin", action = "Index", id = UrlParameter.Optional }
);
If you don't specify this, MVC doesn't know quite what you're looking for and actually expects you to navigate to /admin/admin in order to display the initial view. So change the routing as I've mentioned above and then use this action link to get to FloorController.Create():
#Html.ActionLink("floors", "create", "floor", new { area = "admin" }, null)
To expand a little, with your routing setup this way, your URLs will look like this:
/admin // Executes AdminController.Index()
/admin/floor // Executes FloorController.Index()
Update
Having downloaded Maciej Rogoziński's project, this gives me the same problem that your project currently has. The link from the default action is linking to /admin/admin/, which as I mentioned earlier, is what your project is looking for because no default controller has been specified for the area routing (this also applies to Maciej's project). Specifying the default controller allows you to navigate to /admin, which results in AdminController.Index() being invoked. Without specifying that controller, you can only retrieve this view from routing to /admin/admin, which again, is what Maciej's application is doing.

How do I know which controller this page is hitting?

Pretty new to MVC I have a page on an open source application I have downloaded that is at the url...
http://localhost:51930/admin/login?databaseIssue=true
Obviously Im trying to find which controller and view this maps to in the application. How do I work this out? What should I search for and where to look?
Also how do I work out which actions process this view?
This should help you out. This tool is awesome!
http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx
This guide should get you started. Basically you work with a collection of routes and their arguments, in the global.asax.cs file. The guide there also has a section on custom routes.
By the defaulting routing rules, it's {controller}/{action}/
Which would make the controller in http://localhost:51930/admin/login?databaseIssue=true admin and the action Login.
By convention, MVC routes are generated in form
{app_base}/{controller}/{action}
Check out this stackoverflow question for more information.
So in your case, you'll want to look for an admin.cs class in your Controllers folder.
global.asax is where the route mapping is defined.
You'll see/set something like:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
so by default, your example maps to admin = {controller} and login = {action} and login action method would take the databaseissue=true bit as a parameter.
All these answers are good, except in the case where someone may have created a custom route to the specific url in question. By default, they are all correct, but if a custom route was setup, it could be going to the StackController and referencing the Overflow action.
Like Jamie R Rytlweski suggested above, reference RouteDebugger in your project, add the hook in your global.asax and try going to that page, it will show you a listing of all the routes defined in your application and then show you which routes the current page matches

Categories

Resources