MVC controller action causing 404 not found error - asp.net

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".

Related

Make route work without specifying action name in URL. - MVC

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.

asp mvc4 html helper not navigating to expected page

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.

Adding attribute route breaks config-based route (.NET MVC5)

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

ASP.net MVC 5 Route with two parameter

I want create web application with 2 parameter. Add this Code to RegisterRoutes function:
routes.MapRoute(
"pageroute",
"page/{pageid}/{pagename}",
new { controller = "page", action = "Index", pageid = "", pagename = "" }
);
and add this method in pageController:
public ActionResult Index(int pageid,string pagename)
{
return View();
}
Now when i running application with this parameter
http://localhost:1196/page/4/Pagename
Application run successfully but when running with this parameter
http://localhost:1196/page/4/Pagename.html
Application return 404 error
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
while add .html in parameter return 404 error. why?
Because by default HTML files are not being served through MVC/IIS.
Your application looks for a physical file named Pagename.html and cannot find it there. Hence - 404.
To make it work, you need to setup your IIS to catch requests for files with HTML extension and pass this request to MVC.
EDIT: Here is a similar question where OP found a solution by switching "Managed Pipeline Mode" to "Classic".
Try changing the Route to:
routes.MapRoute(
"pageroute",
"page/{pageid}/{*pagename}",
new { controller = "page", action = "Index", pageid = "", pagename = "" }
);
This will then match everything as in page/1/* so the .html should go via this route.
I was unable to reproduce an issue where a .html file gave a 404 using a scenario similar to the question, so there may be some other routing issue or IIS configuration causing this.

How to do the proper routing in ASP.Net WebAPI

I am developing an application using ASP.Net Web API and to configure application routing, I'm following this method. But in my application, the url i want is the below. "http://localhost/MY/api/user/AllGridData/false/1342006446883/10/1/Id/desc"
I manually typed this url in my browser window and AllGridData method is fired. But when I access it from the application, it tries to access the url like below.
"http://localhost/MY/api/user/AllGridData?_search=false&nd=1342006446883&rows=10&page=1&sidx=Id&sord=desc"
So then the AllGridData method is not fired because of the following exception.
Failed to load resource: the server responded with a status of 400 (Bad Request) "http://localhost/MY/api/user/AllGridData?_search=false&nd=1342006446883&rows=10&page=1&sidx=Id&sord=desc"
My routing for this url in RouterConfig.cs is like this.
routes.MapHttpRoute(
name: "LoadGridApi",
routeTemplate: "api/{controller}/{action}/{_search}/{nd}/{rows}/{page}/{sidx}/{sord}",
defaults: new { _search = UrlParameter.Optional, nd = UrlParameter.Optional, rows = UrlParameter.Optional, page = UrlParameter.Optional, sidx = UrlParameter.Optional, sord = UrlParameter.Optional }
);
Hope you understand the problem. Ultimately what I want is to get the URL like below, so then it AllGridData method is fired.
"http://localhost/MY/api/user/AllGridData/false/1342006446883/10/1/Id/desc"
What am I doing wrong? Is it because of wrong routing code?
My AllGridData method is in a WebAPI controller, not in a MVC controller.
thilok. I just tried something similar, with a simpler routing.
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}/{nd}",
defaults: new {id = RouteParameter.Optional, nd = RouteParameter.Optional}
);
and used jQuery getJson calls to call the following method.
public IEnumerable<Organisation> Get(int id, int nd)
{
using (_unitOfWork)
{
I found that I was able to make calls using all the following Urls
/api/organisations/2/3, /api/organisations/2?nd = 3 and /api/userorganisations/?id=2&nd=3
This also worked when directly calling them from a browser window. (Chrome).
What I have notice that you have wrong is that you have an extra placeholder for action {action}. This should not be there for WebApi routing. This is for MVC routing only. There is no concept of action for WebApi's, as this is all handled by the HttpVerbs.
Further information can be found here
WebApi routing
You can use actions just fine in WebApi too. You just don't need them if you are trying to build something RESTful.
example:
public HttpResponseMessage OpenBill(long billId)
Gets it route from:
routes.MapHttpRoute(
name: "DefaultApiWithActionAndId",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Also, you do not have to specifiy querystrings with more than one route. This is why /api/organisations/2/3 works and /2?nd=3 works.
IMHO you should try to keep the routes as simple as possible, otherwise you are in for a world of hurt if something stops working and you have to debug your routes. So i'd go with the querystring version.
Why you are getting urls that are a querystring I cannot answer. It depends who is making the url. This is how GETs usually are done.

Resources