I have 2 areas in an mvc4 application and I have registered the namespace for each of the areas.
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Intergration_default",
"Intergration/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
constraints: null,
namespaces: new[] { "WebApplication.Areas.Intergration.Controllers" }
);
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Vend_default",
"Vend/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional},
constraints: null,
namespaces: new[] { "WebApplication.Areas.MyController.Controllers" }
);
I can access Intergration/MyController however when I try accessing MyController I get an error
Multiple types were found that match the controller named 'mycontroller'. 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.
What am I doing wrong? do I need to do something extra in the global.asax
Based on the code / description you provided, it sounds like it could be a couple of things:
You have a controller name collision in the root controllers namespace (i.e., in the Controllers folder in the root of the project, not in an area) with another area with no constraint.
More likely, your second area registration for Vend has what looks like an incorrect namespace. Instead of WebApplication.Areas.MyController.Controllers it should be WebApplication.Areas.Vend.Controllers. I bet that there's a controller in your root controllers namespace that shares a controller name with something in the Vend area.
Related
I've read all the questions in Stackoverflow that I could find about this subject that were not so old, and till now I haven't find a solution to my simple case.
I just created 2 controllers in an Area, and I am using the default auto generated area routes.
When I try to access by:
http://localhost:57969/FieldProduction/CustomerProduction/1
I have an exception and with the help of Glimpse information I see that the "1" is been interpreted as the action and not as a parameter....
I When I try to access one of the area controllers with:
http://localhost:57969/FieldProduction/CustomerProduction/?1
The default action "Index" is used, but the contructor variable int? Id is not beeing filled.
Action:
public async Task<ActionResult> Index(int? id)
Default Area Controller Route:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"FieldProduction_default",
"FieldProduction/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
How can I fix this?
I am leaving this question open in order for possible other solutions, but at the moment I was able to solve my problem by writing a custom route in the areaRegistration
//**NEW ROUTE**
context.MapRoute(
"FieldProduction_CustomerProduction",
"FieldProduction/CustomerProduction/{id}",
new { action = "Index", controller = "CustomerProduction", id = UrlParameter.Optional }
);
//**ORIGINAL ROUTE**
context.MapRoute(
"FieldProduction_default",
"FieldProduction/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
Your routing thinks that /1 is action name (but You know this)
You have two options:
1st one: add id parameter like this:
http://localhost:57969/FieldProduction/CustomerProduction?id=1
2nd: Use attribute routing in this controller.
attribute routing
There is 3rd option, You can add regex to Your routing, to identifiy that action is never int.
I am trying to achieve the routings as follow:
http://example.com/Admin/Index
http://example.com/Application/Index
http://example.com/Customers/Index
etc...
I like the ideas of using 'Areas' and want to separate all the codes by using Areas. So, I created my Areas structure like the following screnshot
and the code in ApplicationAreaRegistration.cs is
public override string AreaName
{
get
{
return "Application";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Application_default",
"Application/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
However, I cannot achieve the route I want like
http://example.com/Application/Index
In stead of that it becomes, http://example.com/Application/Application/Index
I tried to change the default routing without {controller} in AreaRegistration
context.MapRoute(
"Application_default",
"Application/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
But I got, Controller is required area.
I know I can easily get http://example.com/Application/Index if I put the Controller in root Controllers Folder. But it means I couldn't group my codes like the Areas anymore and it will be seprated across the MVC Folders.
What I would like to know is, whether I can achieve what I want by using the Areas or am I trying to do which is impossible?
You need to add a default controller name to the route so MVC understands what to put in the controller route value when you take it out of the URL.
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Application_default",
"Application/{action}/{id}",
new { controller = "Application", action = "Index", id = UrlParameter.Optional }
);
}
I want to link to a controller with actually specifying the action parameter. I'm pretty sure this is possible. And got the concept from here:
http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-a-route-constraint-cs
These are the two links:
https://localhost/mvcapplication1/customer/order/index/6463 (WORKS)
https://localhost/mvcapplication1/customer/order/6463 (WANT THIS)
I specified a special rout for this controller (Customer_orders).
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Customer_orders",
"Customer/Order/{orderId}",
new { controller = "MvcApplication1.Areas.Customer.Controllers.Order", action = "Index" },
new[] { "MvcApplication1.Areas.Customer.Controllers" } // only map routes to controllers in the specified namespace
);
context.MapRoute(
"Customer_default",
"Customer/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "MvcApplication1.Areas.Customer.Controllers" } // only map routes to controllers in the specified namespace
);
}
And this is my controller with the namespace:
namespace MvcApplication1.Areas.Customer.Controllers
{
[Authorize]
public partial class OrderController : SupertextController
{
I've also enabled the Route Debugger and according to that my routes are ok. So why do I get a "The resource cannot be found."? Specially since it works if I add "index" to the URL.
In your routes the default value of the controller token should be your controller name without any namespace and without the "Controller" postfix:
So change your route to:
context.MapRoute(
"Customer_orders",
"Customer/Order/{orderId}",
new { controller = "Order", action = "Index" },
new[] { "MvcApplication1.Areas.Customer.Controllers" }
);
I'm trying to use Maarten Balliauw's Domain Route class to map sub-domains to the areas in an MVC2 app so that I have URLs like:
http://admin.mydomain.com/home/index
instead of:
http://mydomain.com/admin/home/index
So far, I've only had partial success. Execution is being routed to the correct controller in the correct area, but it cannot then find the correct view. I'm receiving the following error:
The view 'Index' or its master was not found. The following locations were searched:
~/Views/AdminHome/Index.aspx
~/Views/AdminHome/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
This indicates to me that MVC is looking for the view only in the root views folder and not the views folder within the Area. If I copy the view from the Area's views folder to the root views folder, the page renders fine. This however, completely defeats the purpose of dividing the APP into Areas.
I'm defining the route for the area as:
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "Admin"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.Routes.Add(
"Admin_Default"
, new DomainRoute(
"admin.localhost"
, "{controller}/{action}/{id}"
, new { controller = "AdminHome", action = "Index", id = UrlParameter.Optional }
));
}
}
I'm confused as to why it is finding the controller within the Area fine, but not the view.
OK, I figured it out. After downloading the MVC 2 source code and adding it to my solution as outlined here, I stepped through the MVC code. I found that Routes within areas implement the IRouteWithArea interface. This interface adds an 'Area' property to the RouteData which, not surprisingly, contains the area's name. I modified the DomainRoute class so to implement this interface and added a couple of overloaded constructors that took this additional parameter, and it now works exactly as I wanted it to.
The code for registering my route now looks like this:
context.Routes.Add(
"Admin_Default"
, new DomainRoute(
"admin.mydomain"
,"Admin"
, "{controller}/{action}/{id}"
, new { controller = "AdminHome", action = "Index", id = UrlParameter.Optional }
));
If you have share controller names between your areas and your default routes, and it looks like you do, you may need to identify namespaces when you call MapRoute.
For example, if the top-level namespace of your web application is Web, the RegisterRoutes method in Global.asax.cs file would look something like this:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
null,
new string[] { "Web.Controllers" }
);
and then the RegisterArea moethod of AdminAreaRegistration.cs would look something like this:
context.MapRoute(
"Admin_Default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
null,
new string[] { "Web.Areas.Admin.Controllers" }
);
I have a project that is using MVC areas. The area has the entire project in it while the main "Views/Controllers/Models" folders outside the Areas are empty barring a dispatch controller I have setup that routes default incoming requests to the Home Controller in my area.
This controller has one method as follows:-
public ActionResult Index(string id)
{
return RedirectToAction("Index", "Home", new {area = "xyz"});
}
I also have a default route setup to use this controller as follows:-
routes.MapRoute(
"Default", // Default route
"{controller}/{action}/{id}",
new { controller = "Dispatch", action = "Index", id = UrlParameter.Optional }
);
Any default requests to my site are appropriately routed to the relevant area. The Area's "RegisterArea" method has a single route:-
context.MapRoute(
"xyz_default",
"xyz/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
My area has multiple controllers with a lot of views. Any call to a specific view in these controller methods like "return View("blah");
renders the correct view. However whenever I try and return a view along with a model object passed in as a parameter I get the
following error:-
Server Error in '/DeveloperPortal' Application.
The view 'blah' or its master was not found. The following locations were searched:
~/Views/Profile/blah.aspx
~/Views/Profile/blah.ascx
~/Views/Shared/blah.aspx
~/Views/Shared/blah.ascx
It looks like whenever a model object is passed in as a param. to the "View()" method [e.g. return View("blah",obj) ] it searches for the view
in the root of the project instead of in the area specific view folder.
What am I missing here ?
Thanks in advance.
Solved ! A couple of my "RedirectToAction" calls were not specifying the area name explicitly in the routeobject collection parameter of that method. Weird though, that that is required even though the controllers Redirecting are all in the same area. Also, the HtmlActionLinks work fine when I don't specify the new {area="blah"} in its routeobject collection, so I wonder why the controller action calls to RedirectToAction() need that even though both the calling and the called controller actions are all within the same area.
If you use instead of
context.MapRoute(
"xyz_default",
"xyz/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
use
context.MapRoute(
"xyz_default",
"{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
in your
xyzAreaRegistration.cs
then you don't need to explicitly specify your area in any link...
Add the RouteArea attribute on the Controller class so MVC knows to use the "XYZ" Area for the views (and then you can set the AreaPrefix to empty string so routes do not need to start with "XYZ").
[RouteArea("Xyz", AreaPrefix = "")]
public class XyzController : Controller
{
...
}
If this is a routing problem, you can fix it by registering your area routes first. This causes the routing engine to try matching one of the area routes, before matching a root route:
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
If I force an error by renaming one of my views folders in my areas application, I get a different error than yours:
The view 'Index' or its master was not found. The following locations
were searched:
~/Areas/xyz/Views/Document/Index.aspx
~/Areas/xyz/Views/Document/Index.ascx
~/Areas/xyz/Views/Shared/Index.aspx
~/Areas/xyz/Views/Shared/Index.ascx
...and then the usual root view folders..
..which is the pattern of subdirectories it would search if it thought it was in an area.
Check the generated code at MyAreaAreaRegistration.cs and make sure that the controller parameter is set to your default controller, otherwise the controller will be called bot for some reason ASP.NET MVC won't search for the views at the area folder
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"SomeArea_default",
"SomeArea/{controller}/{action}/{id}",
new { controller = "SomeController", action = "Index", id = UrlParameter.Optional }
);
}
For those who are looking for .net core solution please use
app.UseMvc(routes =>
{
routes.MapRoute(
name : "areas",
template : "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
});`
If you have some code in main project and some code in areas use the following code.
app.UseMvc(routes => {
routes.MapRoute(
name: "areas",
template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Note make sure you have areas defined in your controller
[Area("Test")]
public class TestController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
I just had the same problem and solved it by setting the ascx's 'Build Action' property to 'Embedded Resource'.
Try this code. Do changes in Area Registration File...
context.MapRoute(
"YourRouteName", // Route name //
"MyAreaName/MyController/{action}", // URL with parameters //
new {
controller = "MyControllerName",
action = "MyActionName", meetId = UrlParameter.Optional
}, // Parameter defaults
new[] { "Your Namespace name" }
);