MVC Controller named Controllers throws "Server Error in '/' Application." - asp.net-mvc-3

I'm using ASP.NET MVC 3 (Razor) and have created a Controller named "Controllers" - specifically, the Controller class name is "ControllersController".
Here's a snippet of my "Controllers" Controller:
public class ControllersController : Controller
{
public ActionResult Index()
{
return View();
}
}
In addition to creating the ControllersController class, I created a Razor View (Index.cshtml) that correlates with the ControllersController Index() action. It may be worth noting that I created the Index.cshtml View by right-clicking the Index() method within the Controller and choosing "Add View".
The problem that I am experiencing is, when a browser tries to go to http://localhost/controllers, the following error is thrown:
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: /controllers/
There are two points that I'd like to point out:
The error can be avoided if the
browser explicitly goes to
http://localhost/controllers/index
Controllers that are not named
ControllersController don't force
the browser to specify the /index
action in its URL.
With all the naming conventions in MVC, I'm not surprised that a Controller named Controllers causes some strange behavior. My question is; what do I need to do so that I don't have to specify /index in the browser's URL?

This is because you have a folder called "Controllers" on disk in your project. One option would be to rename that folder to something else. This problem won't exist when you publish your site using the Visual Studio publish option because the Controllers folder won't get pushed. A second more cumbersome solution would be to set routes.RouteExistingFiles = true; in the RegisterRoutes function in your global.asax.cs. You then may want to call route.IgnoreRoutes for items in your content folder, etc.

Stay away from using any current names in your code - the world will be a better place, children wont cry, etc.
"With all the naming conventions in MVC, I'm not surprised that a Controller named Controllers causes some strange behavior. "
If it feels weird - don't do it : )

Apparently, the problem has nothing to do with the name of the Controller (i.e. ControllersController), but rather with the name of the URL route.
In my Global.asax.cs, I added a custom route as follows:
public static void RegisterRoutes(RouteCollection routes)
{
//Route /controllers/ to /Home/Index
routes.MapRoute(
"Controllers",
"controllers/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Notice the the custom route (named "Controllers") routes to the HomeController (not ControllersController).
I would expect that when the browser points to http://localhost/controllers, MVC would return the /Home/Index page. Instead, a 404 error is thrown. However, the route succeeds if the browser points to http://localhost/controllers/index. - This is the same symptoms as I mentioned at the beginning of this post.
Based on this test, I think it's safe to assume that the problem is not with the naming convention of the Controller, but rather with the naming convention of the MVC routing.
To move on with building my application, I'm going to change the name of my ControllersController to ControllerSystemsController. In the meantime, I'm interested to know specifically why the MVC router doesn't work as expected for routes that use "controllers" as the name of the controller. Can anyone shed light on this?

Related

ASP.NET MVC 3: Moved app into virtual directory. What do I have to change?

I have been working on an MVC 3 app. I was using VS 2010's built-in web server.
Today, for various reasons, I was asked to move it into a virtual directory and run it under IIS 7, still on my development PC.
Now that its URL is localhost/MyVirtualDirectory as opposed to localhost:12345, what do I need to change to make routing work, and where?
I'm not using any raw HTML anchor tags or redirects, just #Html.ActionLink and so on. According to what I've read, if I've been doing things the MVC way, this change should have been transparent.
But right at the beginning, the post-authentication redirection fails. On successful authentication, it's supposed to return the result of
this.RedirectToAction("index", "Home")
You guessed it: instead of /MyVirtualDirectory/Home the redirection goes to /Home. Which fails.
So something is missing that needs to be set up. What is it?
In IIS, choose your virtual directory and "Convert to Application." Also, if you are using the default route map in your Global.asax it should read something like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Reasoning: If you put your MVC application in a sub-directory of another application then IIS will consider the root of that other application instead of the root of your MVC application. If that is the behavior that you want (unlikely) then you need to modify your Global.asax to take that into account:
routes.MapRoute(
"Default", // Route name
"MyVirtualDirectory/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

Best way to deal with renaming a controller

Working with ASP.NET MVC3, site is in beta and customer decided to rename one of the controllers.
http://domain.com/foo[/*] -> http://domain.com/bar[/*]
What is the most straightforward way to handle redirecting so I don't break any foo bookmarks?
Keep the old controller around so the old URLs still work.
Or add a rewrite rule. Something like:
domain.com/foo(/[_0-9a-z-]+)
to:
domain.com/bar{R:1}
URL Rewrite in IIS
http://technet.microsoft.com/en-us/library/ee215194(WS.10).aspx
http://www.iis.net/download/URLRewrite
If you are using MVC.NET you probably already have URL Rewrite installed.
Another option would be to register a specific route for the old controller name in the Global.asax.cs.
routes.MapRoute(
"RenamedController", // Route name
"[OldControllerName]/{action}/{id}", // URL with parameters
new { controller = "[NewControllerName]", action = "Index", id = "" } // Parameter defaults
);
Add that before the standard default route, and your new controller should respond to both old and new names.
A 302 redirect would be fine, if you can figure out how to do that in IIS. This screenshot suggests it's not that arduous. Alternately, if you're using Castle Windsor you may want to register an interceptor that uses HttpResponse.Redirect()
REST standard suggests the best way to handle this issue is by returning a 301(Moved permanently request). Stack Overflow Post REST Standard
In .Net I recommend using Controller.RedirectToActionPermanent in your controller. See: ASP.NET, .NET Core
Code Example(should work for both ASP and Core):
public class MyController : ControllerBase
{
public IActionResult MyEndpoint(string routeValues1, string routeValues2)
{
return RedirectToActionPermanent("action", "controller", new { value1 = routeValues1, value2 = routeValues2 });
}
}
using MapRoute doesn't make sense in this case. MapRoute is really meant to provide a custom routing solution throughout the system. Its not really meant to deal with individual Redirects. As far as I'm aware it doesn't actually inform the user they are being redirected. See: Creating Custom Routes (C#)

ASP.NET MVC2 Empty Project Not Loading

My environment consists of Visual Studio 2010 and Windows 7 a few months ago I developed an MVC2 application with no problems however after trying to create a new project recently I received the error below.
I did find the link http://support.microsoft.com/kb/894670 but this is not relevant because I am not using IIS for testing, just F5 to get this working :)
Any ideas or help would be appreciated.
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: /
--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:2.0.50727.4952; ASP.NET Version:2.0.50727.4927
The Empty MVC 2 template application does not define any controllers or views. When you create a new Empty MVC 2 application and immediately run it, you will see the error message you posted.
If you check the Global.asax file, you'll see that the project template automatically registers a default route specifying a default controller named "Home" and a default action named "Index".
To get this to run, right-click on the Controllers folder, then choose Add->Controller... Name the controller "HomeController". You can leave the check box to "Add action methods for Create, Update, Delete..." unchecked.
In the HomeController.cs file, right click in the Index() method and choose Add View...
Leave the View name as "Index", uncheck "Select master page", and then click Add.
In the Index view, you can enter some HTML and run the project; you should now see the page rendered by Index.aspx.
One thing I am not sure of is why your error message lists the .NET Framework version as 2.0. If you still have problems, check the target framework on your project properties.
Make sure that the routes are set properly and that you have default values for a controller and action. For example if you have the following route:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
}
);
Make sure that you have a HomeController with an Index action.

Introducing MVC into ASP.Net - 404 error

I have an existing ASP.Net Application, into which I am attempting to introduce MVC2.
Hopefully I can remember the steps, but what I did was the following:
Created a dummy MVC2 project.
Compared and merged .csproj, resulting in the Add Item commands showing MVC2 items.
Compared and merged the web.config
Compared and merged the global.asax.cs
Added Models, Views and Controllers directories
Added HostController with Index action and Index.aspx (no logic)
Amended route to make /Host/Index the default
So now, when I access the application via the root address http://localhost/MyApp it all works.
But, when I access http://localhost/MyApp/Host/Index I get a 404 error. I get the same result for any of the Controller/Actions I created. The only way I can get them to appear is to use the defaults in the routing configuration. I installed Phill Haack's route debugger and it's doing nothing. Obviously there's some problem with my routing, but I can't figure it out.
Any ideas what I've missed?
Bah... turns out that this is to do with IIS 5.1 and MVC routing.
I resolved it by using the following Routes in my application (note the .aspx extensions).
routes.MapRoute("Root", "", new { controller = "Host", action = "Index" });
routes.MapRoute("Default", "{controller}/{action}.aspx", new { controller = "Host", action = "Index" });
Means I can't have clean routes, but at least it works.

StructureMap controller factory and null controller instance in MVC

I'm still trying to figure things out with StructureMap and one of the issues i'm running into is my Controller Factory class blowing up when a null controller type is passed to it. This only happens when the application builds for the first time, after which every subsequent build works fine. Even when i shutdown Visual Studio and reopen the project (I'm not running this in IIS). It's almost like there is some sort of caching going on. This is what the controller class looks like:
public class IocControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
try
{
return (Controller)ObjectFactory.GetInstance(controllerType);
}
catch (StructureMapException)
{
System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave());
throw;
}
}
}
What could be wrong? Do i need to have every controller registered? Thank you.
Most browser are looking for a favicon.ico when you load a site, and there is probably some caching involved with this behavior, this might explain the odd "Only fail on the first build" thing you mentionned.
In my case this was causing the problem of the null controller type in the controller factory.
Adding a routes.IgnoreRoute("{*favicon}", new { favicon = #"(.*/)?favicon.ico(/.*)?" }); in global.asax makes the error go away, the request should fall through to the filesystem without MVC looking for a favico.ico controller in your code.
Here is a link to Gunnar Peipman post about this
I found out by overriding GetControllerType(string controllerName) in my custom controller factory class and checking what the controllerName value was for each request.
I ran into the same problem with a controller factory built around ninject.
It seems MVC will pass you null for controllertype when it can't resolve a route from the routing table or when a route specifies a none existing controller. I did two things to solve this. You might want to check your route table and add a catchall route that shows a 404 error page like described here .Net MVC Routing Catchall not working
You could also check with the routing debugger what goes wrong.
http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx
I was having the similar problem. I believe it was HTTP requests for nonexistent images, CSS files, etc.
We know the MVC routing first looks to see if the requested file physically exists. If it doesn't then the URL gets tested against the configured Routes. I think the request for an image that didn't physically exist was passed to the Routing engine, and didn't match any routes, so NULL was used.
So to fix it, use FireBug or something to watch for, and fix, broken HTTP requests. During development, I used a route like this to temporarily bypass these issues (all of my resource folders start with an underscore like _Images, _Styles, etc):
routes.IgnoreRoute("_*"); // TODO: Remove before launch
Hope this helps!
What I think you need to do is exactly the same thing that the default MVC controller factory does on the GetControllerInstance method. If you look at the Microsoft source code for DefaultControllerFactory at http://aspnetwebstack.codeplex.com/ you will see that the DefaultControllerFactory throws a 404 Exception when controllerType is null. Here is how we do it based on this information:
public class StructureMapControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return base.GetControllerInstance(requestContext, controllerType);
var controller = ObjectFactory.GetInstance(controllerType);
return (IController)controller;
}
}
Basically this will ensure that, when user enters an invalid route the application handles it as a 404 error.

Resources