Controller namespace not routing correctly - c#

So I am using MVC 5, and is getting this error. This is because I have two areas and they both have a controller with the same name and same method name.
Multiple types were found that match the controller named 'controller1'.
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.
So I understand that I need to add name spaces to my routing. So in Route.config.cs I added this
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "webApp.Controllers" }
);
Then in the application_start() function in global.asax I added ControllerBuilder.Current.DefaultNamespaces.Add("webApp.Controllers");
Then in my areas, where my error is coming from. I have 2 areas, admin and myportal. Both have a AreaRegistration.cs file. In AdminAreaRegistration.cs I have this added
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional },
new[] { "webApp.Areas.Admin.Controllers" }
);
}
In MyPortalAreaRegistration.cs I have this added
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"MyPortal_default",
"MyPortal/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "webApp.Areas.MyPortal.Controllers" }
);
}
From the client side I am making a post call
const otherParams = {
headers: {
"content-type": "application/json; charset=UTF-8"
},
body: JSON.stringify(product),
method: 'POST'
};
console.log(otherParams);
const response = await fetch('/Item/GetDetailPageURL', otherParams)
.then(response => {
response.json();
console.log(response);
window.open(response.url, "_blank");
})
.then(data => console.log(data));
From what I understand this is all I needed to get it work, but it is still complaining about the namespace. Am I misunderstanding/ missing something?

You shouldn't need to change your RouteConfig.cs
All you need to do is to register your area (inside the area folder):
In this example, the area name is admin. You need to write your area registration code inside adminAreaRegistration.cs file which is inside admin folder:
public class adminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"admin_default",
"admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
And then add AreaRegistration.RegisterAllAreas(); to your Global.asax.cs

Besides area registration like Hooman Bahreini said, try to setup your default name spaces as well in the application start.
Try this
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
// in you application start register your default or whatever makes sense Portal Controllers
ControllerBuilder.Current.DefaultNamespaces.Add("webApp.Areas.MyPortal.Controllers");
}
TRUST ME ON THIS -- go to your bin folder and blow away any old dll's "bin" folder completely manually. Sometimes there are stale dll's and don't get cleaned
your routes seem fine, but double check your routes with this answer on routes...

Use Attribute Routing in ASP.NET MVC 5:
[RoutePrefix(“reviews”)]
public class ReviewsController : Controller
{
Somewhere else:
[RoutePrefix(“otherreviews”)]
public class ReviewsController : Controller
{

Related

Constraints in route

So I have ASP.NET MVC application. I would like to configure its routes. Here is my RouteConfig's code:
public static void Register(RouteCollection routes, bool useAttributes = true)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("favicon.ico");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
This route works fine. Besides I have an area in my application and try to configure its routes too. It is my area registration code:
public override void RegisterArea(AreaRegistrationContext context)
{
try
{
context.MapRoute(
name: "SiteSettings_Controller",
url: "SiteSettings/{controller}/{action}/{id}",
defaults: new {action = "Index", id = UrlParameter.Optional,
// here I tried to use #"(UserManagement|Tools|Settings)"
//as constraint but it takes no effect
constraints: new {controller = "UserManagement|Tools|Settings" }
);
}
catch (Exception e)
{
// here I get InvalidOperationException ""
}
}
I would like to restrict controllers in SiteSettingsArea's route but when I go to "localhost/SiteSettings/UserManagement" url I get InvalidOperationException with message "No route in the route table matches the supplied values". I believe that this url corresponds to SiteSettings_Controller route but obviously I am wrong. How could I limit controllers in the route properly?
If you search your codebase for SiteSettings_Controller does it appear anywhere else?
The below code certainly worked for me when I just tested it.
using System;
using System.Web.Mvc;
namespace WebApplication1.Areas.SiteSettings
{
public class SiteSettingsAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "SiteSettings";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "SiteSettings_Controller",
url: "SiteSettings/{controller}/{action}/{id}",
defaults: new
{
action = "Index",
id = UrlParameter.Optional
},
constraints: new { controller = "UserManagement|Tools|Settings" }
);
}
}
}

Routing doesn't find controller with the same name as area

I followed article about Areas in ASP:NET MVC 4 (section How to Avoid Name Conflict). I'm using MVC 5, but I suppose all the features from version 4 are available and should work in version 5.
My directory structure:
File EpicAreaRegistration.cs content:
namespace App1.Web.UI.Areas.Epic
{
public class EpicAreaRegistration : AreaRegistration
{
public override string AreaName
{
get{ return "Epic"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRouteLocalized(
name: "Epic_default",
url: "Epic/{controller}/{action}/{id}",
defaults: new { controller = "Pm", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "App1.Web.UI.Areas.Epic.Controllers" }
);
}
}
}
My project's App_Start -> RouteConfig.cs file content: UPDATE corrected namespace
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Default", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "App1.Web.UI.Controllers" } // according to article namespace must be added here, so ASP.NET router distinguishes between request: e
);
}
}
And finally I have EpicController.cs file in project's directory Controllers:
namespace App1.Web.UI.Controllers
{
public class EpicController : Controller
{
public ActionResult Browse()
{
return View();
}
}
}
When I navigate to: http://localhost:7300/Epic/Pm it works (finds it), but http://localhost:7300/Epic/Browse doesn't work (404 - not found). What have I missed?
My assumption is that request goes through some kind of routing table. If it doesn't find Epic/Browse in Areas, it should move to project's root Controller folder. It's the same analogy as with Views (folder, if not in folder look in Shared, ...)
Additionally I registered all areas in Application_Start
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
....
Make sure your Area controller uses the correct namespace.
Namespace for EpicController is currently:
namespace App1.Web.UI.Controllers
Change it to:
namespace App1.Web.UI.Areas.Epic.Controllers
Your controller is also Epic. So your URL would look like
http://localhost:7300/Epic/Epic/Browse
This may help you to access,
http://localhost:7300/Areas/Epic/Epic/Browse
As It's contained in sub folder.

Not able to route to a view under area in MVC Razor

Problem Statement:
I'm trying to route to a Login view under Area(Test Area) not working.
Exception:
HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this directory
Most likely causes:
A default document is not configured for the requested URL, and directory browsing is not enabled on the server.
If I route to view other than the login view under area it works fine
What I'm doing wrong in routing??
Area:
Test Area Registartion.cs
public class TestAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Test";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Test_default",
"Test/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
Roue Config in App_Start :
If I use default route for login it works fine ,but if I give route to login view under test area it gives HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this director why??
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
// Default Route for Login
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional }
);
//Area View Route for Login
routes.MapRoute(
name: "Test",
url: "Test/{controller}/{action}/{id}",
defaults: new { controller = "Login", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "WebApplication1.Areas.Test.Controllers" }
);
}
}
Global.asax.cs :
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
Database.SetInitializer<WebApplication1.Areas.Test.Models.Test_DB>(null);
}
Try with this:
routes.MapRoute(
name: "Test",
url: "{controller}/{action}/{id}",
defaults: new {controller = "Login", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "WebApplication1.Areas.Test.Controllers" }).DataTokens["area"] = "Test";

"routes.LowercaseUrls = true;" does not work?

I'm having trouble in setting my routes to lowercase by default. For some reason it does not work. I know I can set authorize and home to lowercase myself, but the Admin part (area) will still be capitalized..
#Html.ActionLink("Hello World", "Authorize", "Home")
outputs to
Hello World
Area route
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.LowercaseUrls = true;
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new string[] { "OR.Areas.Admin.Controllers" }
);
context.Routes.LowercaseUrls = true;
}
Default route
public static void RegisterRoutes(RouteCollection routes)
{
routes.LowercaseUrls = true;
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.LowercaseUrls = true;
routes.MapRoute(
name: "Localization",
url: "{lang}/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "OR.Controllers" }
);
routes.LowercaseUrls = true;
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "OR.Controllers" }
);
routes.LowercaseUrls = true;
}
Admin Area configs I tried
// admin/Home/Authorize
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.LowercaseUrls = true;
context.MapRoute(
"Admin_default",
"{area}/{controller}/{action}/{id}",
new { area = "admin", controller = "home", action = "Index", id = UrlParameter.Optional },
new string[] { "ORMebeles.Areas.Admin.Controllers" }
);
context.Routes.LowercaseUrls = true;
}
// admin/Home/Authorize
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.LowercaseUrls = true;
context.MapRoute(
"Admin_default",
"admin/{controller}/{action}/{id}",
new { controller = "home", action = "Index", id = UrlParameter.Optional },
new string[] { "ORMebeles.Areas.Admin.Controllers" }
);
context.Routes.LowercaseUrls = true;
}
Edit
As it seems this is bug with MVC4 - when you set context.Routes.LowercaseUrls = true; and you have Area/Areas context.Routes.LowercaseUrls = true; won't take any effect, where should we report it or how can we get it fixed?
This is bug related to MVC4 and will be fixed in MVC5 release. Routes.LowercaseUrls does not affect areas. More info here.
Meanwhile you can use LowercaseRoutesMVC or
LowercaseRoutesMVC4 if you need WebApi support.
I tried Several attempts to get this particular boolean flag to work with an MVC3 project with no luck. The ONLY way I could get it to work was to create an MVC4 application project and set the flag in the RouteConfig.cs file in the app start. The really bad part is it lowercased the urls across the site automatically for me until I added an area, then it broke everywhere. Once I excluded the newly added area from the project and reran, the urls were lowercased again.
Something is wonkey with the use of that flag. I would recommend downloading the nuget package for lowercasing urls. It seems as if they haven't quite worked out the kinks in this part of the new framework.
Sorry I couldn't be of more help.
UPDATE: IN AN MVC4 application
Create a new blank MVC4 application and add an Area Called Test, with a Test.cshtml View and a TestController.cs controller.
So I figured out something... though I am not sure if it's a reasonable solution. After playing with the route registration routines, having the areas in the project doesn't break the lowercase functionality.
namespace MvcApplication1.Areas.Test
{
public class TestAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Test";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
//This line breaks the functionality in the area registration.
context.MapRoute(
"Test_default", // Route name
"Test/{controller}/{action}/{id}", // URL with parameters
new { controller = "Test", action = "Index", id = "" }, // Parameter defaults
new string[] { "MvcApplication1.Areas.Test.Controllers" } //namespace
);
}
}
}
A workaround:
Comment out the lines
//context.Routes.LowercaseUrls = true;
//context.MapRoute(
// "Test_default", // Route name
// "Test/{controller}/{action}/{id}", // URL with parameters
// new { controller = "Test", action = "Index", id = "" }, // Parameter defaults
// new string[] { "MvcApplication1.Areas.Test.Controllers" } //namespace
// );
In RouteConfig.cs
namespace MvcApplication1
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.LowercaseUrls = true;
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
"Test_default", // Route name
"Test/{controller}/{action}/{id}", // URL with parameters
new { controller = "Test", action = "Index", id = "" }, // Parameter defaults
new string[] { "MvcApplication1.Areas.Test.Controllers" } //namespace
);
}
}
}
In The Area Controller Action Method
public ActionResult Index()
{
// Key if statement to make sure the area maps correctly
if (!this.ControllerContext.RouteData.DataTokens.ContainsKey("area"))
{
this.ControllerContext.RouteData.DataTokens.Add("area", "Test");
}
return View("Test");
}
Resulting HTML for the links in the main page of the project
<ul id="menu">
<li>Home</li>
<li>About</li>
<li>Contact</li>
<li>Test</li>
</ul>
Notice however the query string variables are not lowercased and it is not an seo friendly url. However it does find the view. This is as close as I've been able to come using that flag and having the urls go to lowercase.
As I known, LowercaseUrls = true is only available in .NET4.5, maybe you can just write some extensions for lowercase urls. you can refer to making URL lowercase. Any easy or builtin way for detail info.

Asp.net MVC 2 Areas. Only one will work

This is my goal:
I need to two (or more) "Areas" for my MVC web app. They would be accessed like so:
/* Home */
http://example.com/
http://example.com/about
http://example.com/faq
http://example.com/contact
/* Admin */
http://example.com/admin
http://example.com/admin/login
http://example.com/admin/account
http://example.com/admin/ect
I would like to organize the project like the following:
MyExampleMVC2AreasProject/
Areas/
Admin/
Controllers/
Models/
Views/
Home/
Shared/
Site.Master
Web.Config
AdminAreaRegistration.cs
Web/
Controllers/
Models/
Views/
Home/
Shared/
Site.Master
Web.Config
WebAreaRegistration.cs
Global.asax
Web.Config
So, in Global.asax I have:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
Here is WebAreaRegistration.cs
using System.Web.Mvc;
namespace MyExampleMVC2AreasProject.Areas.Web
{
public class WebAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Web";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"WebDefault",
"{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
'AdminAreadRegistration.cs' is set up the same but the url param is Admin/{action}/{id}.
With the setup above the Web "Area" works great (example.com/about, example.com/contact, etc).
What do I need to do to get the Admin "Area" hooked up with the routes the way I want them? I just get 404ed now.
I've tried every combination of routes, routes w/namespaces, URL Parameters, parameter defaults, etc, I could think of. I have a feeling I'm missing something pretty basic.
I use this AreaRegistrationUtil class. It automatically registers anything which inherits AreaRegistration in any assembly you specify. As an added bonus, it's WAY faster than AreaRegistration.RegisterAllAreas because it only looks at the assembly you specify.
You probably need to set your namespaces on all your area registrations.
Example
context.MapRoute(
"Admin_default",
"admin/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new string[] { "MyExampleMVC2AreasProject.Areas.Admin.Controllers" } // This is area namespace
);
My current solution is here: http://notesforit.blogspot.com/2010/08/default-area-mvc-2.html
I don't like it and would love to get a better solution.
-- copied from URL above:
Implement your Areas as usually, register any routes that you need.
For example:
public class PublicAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Public";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Public_default",
"Public/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional, }
);
}
}
And:
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new {controller = "Overview", action = "Index", id = UrlParameter.Optional }
);
}
}
It's important, that URL should have any prefix, for example http://site.com/PREFIX/{controller}/{action}, because prefix of default Area will be cropped
Next in Global.asax.cs:
public class MvcApplication : System.Web.HttpApplication
{
public static string _defaultAreaKey = "DefaultArea";
public static void RegisterDefaultRoute(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//reading parameter DefaultArea from web.config
string defaultArea = ConfigurationManager.AppSettings[_defaultAreaKey];
//check for null
if (String.IsNullOrEmpty(defaultArea))
throw new Exception("Default area isn\'t set");
//select routes from registered,
//which have DataTokens["area"] == DefaultArea
//Note, each Area might have more than one route
var defRoutes = from Route route in routes
where
route.DataTokens != null &&
route.DataTokens["area"] != null &&
route.DataTokens["area"].ToString() == defaultArea
select route;
//cast to array, for LINQ query will be done,
//because we will change collection in cycle
foreach (var route in defRoutes.ToArray())
{
//Important! remove from routes' table
routes.Remove(route);
//crop url to first slash, ("Public/", "Admin/" etc.)
route.Url = route.Url.Substring(route.Url.IndexOf("/") + 1);
//Important! add to the End of the routes' table
routes.Add(route);
}
}
protected void Application_Start()
{
//register all routes
AreaRegistration.RegisterAllAreas();
//register default route and move it to end of table
RegisterDefaultRoute(RouteTable.Routes);
}
}
Do not forget add parameter to web.config:
<configuration>
<appSettings>
<add key="DefaultArea" value="Public"/>
</appSettings>
<!-- ALL OTHER-->
</configuration>

Categories

Resources