I am generating a link using the below code
#Html.ActionLink("Search", "Index", "Properties")
on the client side this renders
Search
Looking at the above link I expected to got to
controller: Properties
action: Index
When I click the link I am navigated to http://localhost:49878/Properties/ and I get the error
HTTP Error 403.14 - Forbidden
The Web server is configured to not list the contents of this directory.
If I navigate to http://localhost:49878/Properties/Index I get my expected page.
Why?
I have looked at RouteConfig to try and understand this and looking at the default route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I thought the below would resolve the issue, but it didn't, why?
routes.MapRoute(
name: "Search",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Properties", action = "Index", id = UrlParameter.Optional }
);
You only see a Properties folder in your solution like this:
But if open project folder like this:
You can see two folders in two paths:
Root
View folder
The routing system checks the file system to see if a URL matches a file/folder on the disk. If it finds a match, the routing is ignored and the request bypassed any route entries so that the file will be served directly.
To fix this you can set the RouteExistingFiles property to true in your RouteConfig:
routes.RouteExistingFiles = true;
You cannot use Properties as it's the name of the folder that has AssemblyInfo.cs . So kind of restricted name.
Add this to
routes.RouteExistingFiles = true;
RegisterRoutes in RouteConfig to ignore physical paths (although this will have some complications for static files, do test it thoroughly).
Better approach is renaming your controller and use it not sure if there is something else that can be done.
Related
I have the following controller within my MVC project:
public class PressController : Controller
{
// GET: Press
public ActionResult Index()
{
return File("../press/FFF_PRESS.zip", ".zip");
}
}
My routes
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
When I load the site my URL is as follows:
www.example.com
Which displays the home page correctly, when I click on the following Action <li class="footer__navEl"><a href='#Url.Action("Index", "Press")'>PRESS</a></li>
I would like the URL to be
www.example.com/press
and return the zip file.
However when I click this Action I get the following:
HTTP Error 403.14 - Forbidden
The Web server is configured to not list the contents of this directory.
Yet when I specify
www.example.com/press/index
The .zip file is returned correctly.
Now I added the following to my routes.config:
routes.MapRoute("Press", "Press", new { controller = "Press", action = "Index" });
I still get the same error mentioned above, can someone shed some light into what I might be missing to get this to perform correctly?
HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this directory.
The error indicates you have a physical directory on your web server named press. What is happening is that the web server is returning the directory instead of passing the request on to MVC. The default setting in IIS is not to list the directory's contents, hence the error.
You need to either delete the press directory (recommended), or reconfigure IIS to run the MVC module instead of the directory by using the runAllManagedModulesForAllRequests, which has some caveats.
This isn't a routing problem at all - it is a webserver configuration problem.
NOTE: This is not a duplicate of another question as my first page works fine, it is other pages/actions that are not working.
I've ready many posts so far and nothing comes close. This works just fine when run locally on my development box. After I copy to the server, I see the problem. My default route works fine, I get the expected index page.
public ActionResult Index()
{
return View();
}
My RouteConfig contains:
routes.MapRoute(
name: "AnnualFees",
url: "{controller}/{action}/{id}",
defaults: new { controller = "AnnualFees", action = "Index", id = UrlParameter.Optional }
);
Problems arise when I want to reach anything other than Index. For example, this action causes a 404 not found error:
public ActionResult renderForm()
{
return PartialView("_formPanel");
}
Again, works as it should on my local dev box. But on the server I get Requested URL: /AnnualFees/renderForm 404 error The resource cannot be found.
UPDATE
Ok, doing some more research and trial and error, I discovered something and have a bit more to add.
This app is running under a current website in IIS, where I created a Virtual Folder/application under the website root. If I navigate to www.mysite.com/AnnualFees I get the first page of my MVC app as expected. However, the only way I can get to any other action in my AnnualFeesController, I have to double up the controller name like www.mysite.com/AnnualFees/AnnualFees/renderForm which works but is ugly and not quite right. How can I get rid of the redundancy?
So the problem, as I noted in the comment, is that you have a folder, and under it goes the route. If you do not provide any parts of the route, just calling
www.mysite.com/AnnualFees
this uses all defaults as specified in your route config, and you get the default page. However if you type
www.mysite.com/AnnualFees/ActionName
MVC sees that as controller ActionName and no action no id provided. This does not exist in your app, thus the error.
The root problem here is that websites are not supposed to live under folders, they are supposed to live under top domains. That is, it is not expected that site root URL is www.mysite.com/AnnualFees, it is supposed to be just www.mysite.com. But even that would be fine if you did not have your main controller and IIS folder with the same names, producing unwanted duplication.
You can however change you route to make AnnualFees a default controller. Simply remove the controller part like so:
routes.MapRoute(
name: "AnnualFees",
url: "{action}/{id}",
defaults: new { controller = "AnnualFees", action = "Index", id = UrlParameter.Optional }
);
Now you should be able to use
www.mysite.com/AnnualFees/ActionName
Again, note that in the above URL "AnnualFees" is not a controller name, it is in fact no visible to MVC app at all.
There is however a caveat. Imagine you need to add another controller. Now the default and only route would not work with it. The key is to provide a separate route for this controller, with hardcoded first part
routes.MapRoute(
name: "NewControllerRoute",
url: "NewControllerName/{action}/{id}",
defaults: new { controller = "NewController", action = "Index", id = UrlParameter.Optional }
);
Make sure to put this route before the default one, so that all requests to this controller are routed correctly, and all other requests go to "AnnualFees".
So, we're updating a project from web forms to .NET MVC. To support other applications that deep link into our application, I'm trying to add attribute routes to the relevant controller actions that mimic the old web forms paths.
I have an event action on the Home controller. The configuration has a route for this to remove the controller name.
routes.MapRoute(
name: "eventdetails_nohome",
url: "event/{id}/{occurrenceid}",
defaults: new { Controller = "Home", action = "Event", occurrenceid = UrlParameter.Optional },
constraints: new { id = #"\d+", occurrenceid = #"\d+" }
);
That route works just fine for routes like http://myapp/event/123/456, and the default routing like http://myapp/home/event?id=123&occurrenceid=456 also works.
So far so good, but if I add this route attribute to the action:
[Route("~/ViewEvent.aspx")]
public ActionResult Event(int id, int occurrenceid)
Then the only route that works is http://myapp/ViewEvent.aspx?id=91918&occurrenceid=165045. The routes that worked before start returning
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /event/123/456
I've used the routedebugger extension, and I can verify that even with the attribute route, my old route is still the first to work. So why would I be getting "resource cannot be found" errors?
Note: as a workaround, I've found that I can just do a traditional route configuration like
routes.MapRoute(
name: "Legacy event",
url: "ViewEvent.aspx",
defaults: new { Controller = "Home", action = "Event" }
);
I'm still curious why the attribute route would break existing routes, though, as I thought you were supposed to be able to use both at the same time.
Take a look at Attribute Routing in ASP.NET MVC 5
Another article with the same heading
Attribute Routing in ASP.NET MVC 5
Attribute routes overrides the convention based route. If you use more than one URL for action, you can use multiple route attributes on the action...
[Route("event/{id:int}/{occurrenceid:int}")]
[Route("event")]
[Route("~/ViewEvent.aspx")]
public ActionResult Event(int id = 0, int occurrenceid = 0) {
return View();
}
The following URLs all routed to the above action.
http://myapp/event/123/456
http://myapp/home/event?id=123&occurrenceid=456
http://myapp/ViewEvent.aspx?id=91918&occurrenceid=165045
I have a bigger project with about 9 controllers. Now at the end of the project the url requeirement change. How to deal best with this situation - renaming the controllers seems just too cumbersome ... I need to change all links in servercode and javascript
Your problem can be solved by changing your existing routes. In your global.asax you'll find a code fragment like this
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
That maps an URL '/Controller/Action/Id' to Controller, Action and Id. You can provide routes like this
routes.MapRoute(
"RefactoredRoute", // Route name
"SomeChangedURLBase/{action}/{id}", // URL with parameters
new { controller = "Controller", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
to route requests to /SomeChangedURLBase... to be handled by Controller.
Be aware that these routes should be registered before the default route to avoid that links generated in views point to the default route and generate the old URL.
you could change the routings in global.asax
just change the method RegisterRoutes
here you can find some more informations.
http://www.asp.net/mvc/tutorials/older-versions/controllers-and-routing/asp-net-mvc-routing-overview-cs
http://weblogs.asp.net/scottgu/archive/2007/12/03/asp-net-mvc-framework-part-2-url-routing.aspx
cheers
I've got glimpse.
it's highlighting an empty line on the routes tab
Match Area Url Data constraints DataTokens
True Root -- --
Locally it seems cassini doesn't properly emulate a virtual directory so changing from localhost to localhost/site doesn't seem to grant any additional testing insight.
Local testing
cassini (windows 7 (32 and 64 bit are available))
doesn't seem to use or allow integrated
deploy environments
IIS7 Integrated
Tried a http routing setting to push / to /site however I ran into trailing slash issues (/site would route to /site/site, while /site/ would work as expected
web.config
tried a few ways of setting runAllManagedModules=false with various errors
using <remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" /> that was linked
tried
I need /site (/~) requests to go to ~/Default.aspx
would love for a way to have / go there as well.
How do I do it?
To enable Default.aspx as the default url you just need to remove your route handling so that there's no catch-all route.
By default all MVC 3 projects have:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
This is a catch-all route that will match everything you pass in your url. If you remove this and no path is defined then it will use whatever you set up as your default page in your web.config.
To map /site to Default.aspx you just need to add a special route:
routes.MapPageRoute("SitetoDefault", "site", "~/Default.aspx");
This will see the /site and route it to your default page.
You'll have to be careful when adding any other routes to your routing table. All of them will have to have a controller defined or you'll have to add a routing constraint. Something like this:
//controller defined
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
//route constraint
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new {
controller = "Home",
action = "Index",
id = UrlParameter.Optional
}, // Parameter defaults
new { controller = "^(products)|(account)|(home)$" }
);
Here is more detail on creating more complex routing: http://www.asp.net/mvc/tutorials/creating-a-custom-route-constraint-cs