MVC - Application root appears twice in url using Url.Content/Url.Action - asp.net-mvc

I have several mvc applications on the same domain, each have their own directory.
mydomain.com/app1
mydomain.com/app2
etc..
When using Url.Content() and Url.Action() when at the root level, 'app1' part is repeated twice in the urls.
// code used to generate the links
<%= Url.Action("tetris", "Apps") %>
Page Url: mydomain.com/app1/
rendered link (broken): mydomain.com/app1/app1/Apps.aspx/tetris
application root appears twice in the rendered url when at the root directory
Page Url: mydomain.com/app1/home.aspx/
rendered link (works): mydomain.com/app1/Apps.aspx/tetris
application root appears once - everything works as expected
my routes - I'm using the routes from Phil haacks blog post
routes.MapRoute(
"Default",
"{controller}.aspx/{action}/{id}",
new { action = "Index", id = "" }
);
routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "Index", id = "" }
);
Any ideas?

That is because applications process web.configs in order of inner most director to outer most directory.
You have two options to fix this behavior.
Specify the namespaces you want the routes to apply to either in the root directory or your sub-directories. http://msdn.microsoft.com/en-us/library/dd504958.aspx
routes.MapRoute(
"Root", "", new {...},
new[] { "MyNamespace.For.Root" }
);
Or in the root directory specify your sub-directories as ignored routes using. http://msdn.microsoft.com/en-us/library/dd505203.aspx
routes.IgnoreRoute("/app1");
routes.IgnoreRoute("/app2");

When I had this issue it was because someone used RouteArea["app1"] attribute on the Controller but also included it on the action GET["apps1/Detail"] instead of just GET["Detail"]

Related

Asp.Net MVC localizing routes with default language

I need to provide language specific routes for my Asp.Net MVC application. The language should be part of the Url Path (http://myapp/en/Blog) and when it is ommitted the default language have to be used.
http://myapp/en/Blog -> Blog in the English version
http://myapp/Blog -> Blog in the Default (portuguese) Language version
To address this issue I created two Routes bellow:
routes.MapRoute(
name: "Default.lang",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { lang = #"^[a-zA-Z]{2}$" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
The routes are working as expected but I'm getting weird results when I try to use the Url.RouteUrl method to get alternative language urls.
Example 1 - Path: /
url.Action("Index", "Blog") // returns "/Blog" that is OK
url.Action("Index", "Blog", new { lang = "en" }); // returns "/en/Blog" that is also OK
Example 2 - Path: /en
url.Action("Index", "Home") // returns "/en/Blog" (??????????) Not OK
url.Action("Index", "Home", new { lang = "en" }); // returns "/en/Blog" that is OK
As you can see I get a wrong result when I access the url http://myappurl/en and try to use the Url.Action method without pass any route value (same result with Url.RouteUrl)
Does anyone knows what is wrong with my routes?
[EDIT] I'm not sure if the issue is related to the route because I've tested the routes using "en" as first route's constraint and I got the same result.
After some digging inside System.Web.Mvc and System.Web.Routing source code I found that this behavior is expected. I presume that it is designed to correctly work in applications running inside Virtual Directories.
This can be confirmed in this answer that I found when was researching if someone else had the same problem with virtual path and route resolution.
Workaround
Use named route resolution with Url.RouteUrl method that has and different implementation and works as expected.
Example:
var blogDefaultUrl = url.RouteUrl("Default", new {action = "Index", controller = "Blog"});
var blogLangageSpecifictUrl = url.RouteUrl("Default.lang", new { action = "Index", controller = "Blog", lang = language });
I was avoiding to use named routes because my application design is a little bit more complicated than I demonstrated above. By this reason I have to discover at run time the route that matches the Request.Url and from that point I call the RouteUrl to get the alternative languages url to the content.

ASP.NET Core map route to static file handler

I'm working on a ASP.NET Core website (previously named ASP.NET 5 / vNext) with Angular. In order for Angular to work I need to have a catch-all route:
app.UseStaticFiles();
app.UseMvc(routes =>
{
// Angular fallback route
routes.MapRoute("angular", "{*url}", new { controller = "Home", action = "Index" });
});
I also have a few files/folders in wwwroot, like:
wwwroot/app
wwwroot/assets
wwwroot/lib
When any requests are made to these paths, for example http://example.com/assets/css/test.css, and the file (test.css) does NOT exist, it should not continue to the fallback route. It should return a 404.
Right now, if the file does not exist it returns the Angular HTML. So, how can I tell it that any path that starts with '/assets' should only be routed / served by UseStaticFiles?
This seems to work:
app.MapWhen(
context => {
var path = context.Request.Path.Value.ToLower();
return
path.StartsWith("/assets") ||
path.StartsWith("/lib") ||
path.StartsWith("/app");
},
config => config.UseStaticFiles());
However, I'm not sure if there are any performance (or other type of) implications. I'll update if I come across any.
It is strange that this common case (since many use SPA) is not covered almost anywhere and everyone has to invent something. I have found that the best way to do that is to add constraint (e.g. do not use the route if there is /api or "." in the path). Unfortunately this is not supported out of the box, but you can write this constraint yourself or copy the one I wrote from here.
There are a bit more details in this post. But generally the code looks like this:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "api",
template: "api/{controller}/{action}");
routes.MapRoute(
name: "angular",
template: "{*url}",
defaults: new {controller = "Home", action = "Index"},
constraints: new {url = new DoesNotContainConstraint(".", "api/") });
});
P.S. Perhaps this constraint exist out of the box now, but I have not found one. Alternatively a RegEx can be used, but simple one should be way faster.
If you are using attribute template routing then you can apply this elegant solution:
[HttpGet("")]
[HttpGet("{*route:regex(^(?!skipped).*$)}")]
public async Task<IActionResult> Default(string route) { throw new NotImplementedException(); }
So all routes started with skipped will be ignored by this action.
If you want multiple prefixes or anything else then just update regex for your needs.
First Get attribute is needed to handle root of site (in this case route variable is null).

MVC routing requiring ".cshtml" in URL

I have an MVC4 website running fine on dev. When trying to publish to production routing doesn't work. The only rule I have is the default:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "General", action = "Index", id = UrlParameter.Optional }
);
However, on production server (IIS7.5 - just like dev) any of the following fails on 404:
<domain>/Home
<domain>/Home/Index
Plain <domain>/ fails on 403.
NOTE: All this while using route debugger
Playing around I stumbled upon the following curiosity:
<domain>/Home/Index.cshtml/3
Actually brought me to the route debugging page, claiming to match on
controller Home
action Index.cshtml
id 61
More playing showed that it doesn't matter where the ".cshtml" is, it works as long as it's there. e.g. <domain>/.cshtml/Index/4 matched
controller .cshtml
action Index
id 4
Why would it require a ".cshtml" string, and what can I do about it?

Can .net mvc routing cause JavaScript errors?

I am having a lot of trouble using routing infrastructure of asp.net mvc2. I have following routes registered in my global.asax file
routes.MapRoute(
"strict",
"{controller}.mvc/{docid}/{action}/{id}",
new { action = "Index", id = "", docid = "" },
new { docid = #"\d+"}
);
routes.MapRoute(
"default",
"{controller}.mvc/{action}/{id}",
new { action = "Index", id = "" },
new { docConstraint = new DocumentConstraint() }
);
The problem is with first route ("strict"). Three kind of urls can match first route. mycontroller/23/myaction, mycontroller/23/myaction/12 or mycontroller/23/mvaction/stringid. If I try to use this route without specifying value of id everything works fine for example:
Html.ActionLink("Link text", "ActionName", new{docid = 23});
Everything goes well, but if I use links like:
Html.ActionLink("Link text", "ActionName", new{docid = 23, id = 223})
This will produce url currentcontroller.mvc/23/ActionName/223 that is absolutely correct but when it loads the page it gives a JavaScript error in jquery1.4.2.min.js file.
This is strange: if I change id to someid =223 it will reflect in query string and there will be no JS error.
Edit: I have done some further debugging and found when both id and docid are mentioned in route values one thing is ignored in global.asax that is the ignore path.
routes.RouteExistingFiles = false;
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.ignoreRoute is totally bypassed and I can see names of JS files in route value dictionary while debugging in my controller.
it gives javascript error in
jquery1.4.2.min.js file
The most likely cause for this is that something you are displaying on the page is different and you are performing an action that is causing the error. Can you supply enough of a sample from the rendered page to show what you are using jQuery for?
If we drag scripts from solution explorer to site.master it results in following output
<script type="text/javscript" src="../../scripts/jquery.min.js"></script>
The leading dots (..) are creating the problem. Putting source path in url.content or using /scripts instead of ../../scripts will solve the problem because these leading periods are forcing them to match some route in global.asax.

Asp.Net MVC Url.RouteUrl Problem on Windows 2003 vs. Visual Studio 2008

I'm seeing a difference in the output from Url.RouteUrl between my development machine and my deployment server. I'm running Visual Studio 2008 and my deployment box is Windows 2003 Server. I have configured the Global.asax.cs to run with the .aspx extension in my routing tables. However, when I use the "Search-Basic" named route, there is no output from Url.RouteUrl("Search-Basic", new {category = "Test", searchExpression = "search this"})
View Code:
<%= Url.RouteUrl("Search-Basic", new {category = "test", searchExpression="search this"}) %>
Global.asax.cs Code:
// routes for IIS 6 and version below
routes.MapRoute(
"Search-Basic",
"Search.aspx/Basic/{category}",
new { controller = "Search", action = "Basic", category = "All" }
);
routes.MapRoute(
"Default", // Route name
"{controller}.aspx/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "Index", id = "" }
);
On my development box, I get the expected output: /Search.aspx/Basic/Test?searchExpression=search%20this
However, on my deployment server I get no output at all. One difference perhaps is that I'm running the application in a virtual directory on my deployment server; something like: http://testmachine.com/sm/testappname/ where "/sm" is a virtual directory and "/testappname" is a virtual directory holding my application.
Any ideas?
Thank you kindly.
Are you running the same version of ASP.NET MVC because there is a bug in the RC1 (non-refresh) that causes this behavious when you have a route where e.g. the controller is not specified in the route:
The other regression is that in some
cases, the RouteUrl (and thus
RouteLink) methods return an empty
string when you specify a route name,
but the route has default parameters
which are not parameters in the URL.
For example, if you have the following
route:
routes.MapRoute("route-name", "foo/bar", new {controller="Home", action="index"});
Notice that controller has default
value, but is not part of the URL. If
you then specify:
<%= Url.RouteUrl("route-name") %>
You might expect that it would use
that route to render the URL, but it
doesn’t. This bug was introduced when
we refactored all our url generating
helpers to call into a common method.
It turns out, however, that our
RouteUrl methods (aka non-MVC
specific) should have subtly different
behavior than the MVC specific methods
(such as Action). We added a flag to
the common method so that this
difference is taken into
consideration. This was a fix that did
not have a large surface area.
See http://haacked.com/archive/2009/01/30/aspnetmvc-refresh.aspx

Resources