Multiple types were found that match the controller named 'Home'. (Two Areas, Same controller name) - asp.net

This is probably a duplicate to many but the obvious answers in them do not solve my problem.
I get:
Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
The request for 'Home' has found the following matching controllers:
App.Web.Controllers.HomeController
App.Web.Areas.Mobile.Controllers.HomeController
I've setup a default namespace for my HomeController in Global.ascx.cs:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new string[] { "App.Web.Controllers.HomeController" }
);
(Verified that App.Web.Controllers.HomeController is not a typo).
And also registered the Mobile's HomeController in MobileAreaRegistration:
public override void RegisterArea(AreaRegistrationContext context) {
context.MapRoute(
"Mobile_default",
"Mobile/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
Therefore, why is it that I still see the error message? I've built/cleaned and ran again. Still the same outcome.
This is how I register my routes:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}

In your Global.asax route registration for obvious reasons replace:
new string[] { "App.Web.Controllers.HomeController" }
with:
new string[] { "App.Web.Controllers" }
That's a namespace constraint that you should use there, not a specific type.

Related

.NET MVC 5 Only one area not working under IIS

I have problem with one area in my project called 'Reports'. I always get 404 error when I try to access some controller from this Area. This problem only occurs when I run my application on local IIS (Windows 8.1). On other machine (windows 7 and local IIS) everything is ok. Even on this windows 8.1 machine, but IIS Express everything is working well.
I was trying to clear temp files, but no resuls.
Areas are registed such like this:
public class ReportsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Reports";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Reports_default",
"Reports/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
And in Global.asax, Application_start() method:
AreaRegistration.RegisterAllAreas();
I dont know where could be the problem. Do you have any ideas?
Check event viewer. I had this problem and the 'Reports' URL was a virtual directory having to do with SQL Server Reporting Services.
Try this:
public class ReportsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Reports";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Reports_main",
"Reports/{controller}/{action}/{id}",
new { area = "Reports", controller = "Home", action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"Reports_default",
"Reports/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
The Reports_default routing rule sets Index to be the default action for a given controller.
You need to add another Reports_main rule that will set a default controller when you access the root of the area e.g. /Reports. In this rule I assume that the default controller is Home but you can change that to fit your project.
The default AreaRegistration scaffold by Visual Studio does not include a default for controller, meaning that providing a controller in the URL is required.
/Reports/Home // This works (if you have a home controller)
/Reports // This doesn't work
To make the controller optional, you need to provide a default.
public class ReportsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Reports";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Reports_default",
"Reports/{controller}/{action}/{id}",
// Note that controller is defaulted to Home
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Note also that the order in which routes are registered is the same that they will be executed for the entire application. Typically, this means that you must call AreaRegistration.RegisterAllAreas() before you call RouteConfig.RegisterRoutes(RouteTable.Routes).
The answer provided by Tasos will also work, but is incorrectly configured:
Specifying a default area within an AreaRegistration is redundant and unnecessary.
Reports_default in his example is an unreachable execution path, which makes it also redundant and unnecessary.

Asp.Net WebApi Routing 404. Controller becomes "Api"

I am trying to reach a specific webapi action using: api/error/LogJsError with some formdatacollection. I have an ErrorController like this:
public class ErrorController : ApiController
{
[System.Web.Http.HttpPost]
public void LogJsError(FormDataCollection form)
{
var s = form.Aggregate("Javascript error: message", (current, i) => current + (": " + i.Value));
new Logger(HttpContext.Current).LogException(new Exception(s));
}
}
and the routes are configured like this:
config.Routes.MapHttpRoute(
name: "ApiWithAction",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
In WebApiConfig.Register and
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
inside the RouteConfig.RegisterRoutes
But whatever i do the routecollection returns controller = "Api" which thus results in a 404. What am i doing wrong, why is the api route not uses?
Duuuh...i found the answer right after posting it on: https://msdn.microsoft.com/en-us/library/cc668201%28v=vs.140%29.aspx
Note this: "To avoid having the wrong handler handle a request, you must consider all these conditions when you define routes. The order in which Route objects appear in the Routes collection is significant. Route matching is tried from the first route to the last route in the collection. When a match occurs, no more routes are evaluated. In general, add routes to the Routes property in order from the most specific route definitions to least specific ones."
My MVC route (eg: {controller}/{action}/{id}) was added to the routecollection before the (more specific) WebApi route (eg: api/{controller}/{action}/{id}). So instead of using:
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configure(WebApiConfig.Register);
In Application_Start(), use:
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);

asp.net mvc 3 areas and url routing configuration

I have problem with create ulr routing for asp.net mvc3 application.
My project has this structure :
Areas
EmployeeReport
Controllers
Report
Views
Report
List
....
Controllers
Login
Viwes
Login
...
EmployeeReportAreaRegistration.cs :
public class EmployeeReportAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "EmployeeReport";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
var routes = context.Routes;
routes.MapRoute(null, "vykazy/vykazy-zamestnance", new { Area = "EmployeeReport", controller = "Report", action = "List" });
}
}
Global.asax :
routes.MapRoute(null, "prihlasit", new { controller = "Login", action = "Login" });
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Default", action = "Welcome", id = UrlParameter.Optional });
When i try load "http://localhost/app_name/vykazy/vykazy-zamestnance
i get this exception :
The view 'List' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Report/List.aspx
~/Views/Report/List.ascx
~/Views/Shared/List.aspx
~/Views/Shared/List.ascx
~/Views/Report/List.cshtml
~/Views/Report/List.vbhtml
~/Views/Shared/List.cshtml
~/Views/Shared/List.vbhtml
Well, where I do mistake ?
Thanks
revised answer:
Adding to Context.Routes directly means it loses any information about Areas.
Either use AreaRegistration.MapRoute (which is overriden to put in the Area information).
context.MapRoute(...);
Or put the area in the DataTokens parameter (not the defaults parameter as you have done here)
context.Routes.MapRoute("", "url", new {...}, null, new {area = this.AreaName});
Your folder structure for your area should look like so:
Areas
EmployeeReport
Controllers
Views

Asp.net MVC RenderAction method in multiple controller

I am doing some plugin kind of work using asp.net mvc.
I have two plugins(mvc projects) Say users and home. In both the plugins, I have Home Controllers. Yes the names are home controller in both the plugins(projects). When I build the project the Dlls are copied to the host project (third one).
this is home plugin
namespace Plugin.Home.Controllers
{
public class HomeController : Controller
{
public string Index()
{
return "Home from home";
}
public string JustATest()
{
return "Just a test from home";
}
}
}
Here is another controller in different project(User Plugin)
this is home controller
namespace Plugin.Users.Controllers
{
public class HomeController : Controller
{
public string Index()
{
return "Home from Users";
}
public string JustATest()
{
return "Just a test from Users";
}
public string JustAnotherTest()
{
return "Just another test from Users";
}
}
}
In global.asax I have register routes using namespaces.
routes.MapRoute(
"Default", // Route name
"Home/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "Plugin.Home.Controllers" }
routes.MapRoute(
"Users", // Route name
"users/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, new[] { "Plugin.Users.Controllers" }
);
I can access all the routes in the browser without any problem.
Now the problems
I try to use #{Html.RenderAction("JustATest","Home");}
It only renders from the home controller in home module. How can i render it from Users module.
It throws an exception saying method not found in home controller,
when I say #{Html.RenderAction("JustAnotherTest","Home");}
At what stage I can check if a given controller has the given method or not (Some ControllerFactory). Or how can i make sure it picks up the right controller.
Help will be appreciated.
Regards
Parminder
If you really need to save controller names both HomeController, i see simple solution to use hack like this:
routes.MapRoute(
null,
"{home}/{action}/{id}",
new { controller = "Home", action = "Index", home="Home", id = UrlParameter.Optional });
routes.MapRoute(
null,
"{home}/{action}/{id}",
new { controller = "Home", action = "Index", home="Users", id = UrlParameter.Optional }
);
And you can access to this actions both by url and with RenderAction:
#{Html.RenderAction("JustATest","Home", new {home="Home"});}
#{Html.RenderAction("JustATest","Home", new home="Users");}
But I think that problem is artificial (because it is more hard that you imagine), and you use means only for using means, but not for solving real problem. For real plugin architecture you need to create at least:
1. Custom Route Constraint for checking, that controller type is from assembly, where controller was defined.
2. Installer, that will install all routes independently of main application
3. Create unit tests for each plugin application Routes to ensure that all routes, that was installed from plugins, that do not know anything about each other, works properly (and don't break each other).
I recommend to take your controllers at main web application and give them different names.
See the format used here:
render action with lambda
#Html.RenderACtion<Plugin.Home.Controllers.HomeController>(...)
Edit
I see your issue now. It's that they are dynamically loaded at runtime and hence the names aren't known when you compile. Check out using DefaultControllerFactory as mentioned in various postings here:
How to achieve a dynamic controller and action method in ASP.NET MVC?

how to simulate IgnoreRoute in my custom MvcRouteHandler

In my ASP.NET MVC3 App I try simulate "routes.IgnoreRoute("...")"
I create CustomMvcRouteHandler:
public class CustomMvcRouteHandler: MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
// do something
....
return base.GetHttpHandler(requestContext);
}
}
in my Global.asax.cs file i have:
protected void Application_Start()
{
// ............
RegisterRoutes(RouteTable.Routes);
// ............
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("elmah.axd");
//routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
).RouteHandler = new CustomMvcRouteHandler();
}
How can I do this ?
I'm not entirely sure what you mean in your question, but I'll try to answer it...
To simulate an IgnoreRoute all you need to do is associate an instance of the StopRoutingHandler from your route. If you're using the built-in ASP.NET "Route" class then you would do something like this:
routes.MapRoute(
"Ignore-This", // Route name
"ignore/{this}/{pattern}" // URL with parameters
).RouteHandler = new StopRoutingHandler();
Anything that matches that pattern will cause the routing system to immediately stop processing any more routes.
If you want to write your own custom route (for example, a new route type that derives from RouteBase), then from its GetRouteData method you need to return the StopRoutingHandler.
#Eilon is the correct answer. Here is an alternative syntax that feels more MVCish.
routes.Add("Ignore-This",
new Route(
"ignore/{this}/{pattern}",
new StopRoutingHandler())
);

Resources