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>
Related
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
{
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" }
);
}
}
}
I have a custom routing class which I added to the RouteConfig
public static class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(new CustomRouting());
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
The CustomRouting class looks like this:
public class CustomRouting : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var requestUrl = httpContext.Request?.Url;
if (requestUrl != null && requestUrl.LocalPath.StartsWith("/custom"))
{
if (httpContext.Request?.HttpMethod != "GET")
{
// CustomRouting should handle GET requests only
return null;
}
// Custom rules
// ...
}
return null;
}
}
Essentially I want to process requests that go to the /custom/* path with my custom rules.
But: Requests that are not "GET", should not be processed with my custom rules. Instead, I want to remove the /custom segment at the beginning of the path and then let MVC continue with the rest of the routing configured in RouteConfig.
How can I achieve that?
You can start by filtering "custom" prefixed requests in an HttpModule
HTTP Handlers and HTTP Modules Overview
Example :
public class CustomRouteHttpModule : IHttpModule
{
private const string customPrefix = "/custom";
public void Init(HttpApplication context)
{
context.BeginRequest += BeginRequest;
}
private void BeginRequest(object sender, EventArgs e)
{
HttpContext context = ((HttpApplication)sender).Context;
if (context.Request.RawUrl.ToLower().StartsWith(customPrefix)
&& string.Compare(context.Request.HttpMethod, "GET", true) == 0)
{
var urlWithoutCustom = context.Request.RawUrl.Substring(customPrefix.Length);
context.RewritePath(urlWithoutCustom);
}
}
public void Dispose()
{
}
}
Then you can have your routes for "custom" urls
routes.MapRoute(
name: "Default",
url: "custom/{action}/{id}",
defaults: new { controller = "Custom", action = "Index", id = UrlParameter.Optional }
);
Note: Don't forget to register your HttpModule in your web.config
<system.webServer>
<modules>
<add type="MvcApplication.Modules.CustomRouteHttpModule" name="CustomRouteModule" />
</modules>
</system.webServer>
I've been reading a lot about this problem, and I can't figure this out.
Everything is pretty straightforward with routing and ASP .NET MVC, but I'm stuck with this.
The problem is that I'm trying to make a GET to a given url with this form:
{area}/{controller}/{action}
But the {area} is not being registered. My default route is not working either (not working in the sense that I need to go to localhost:port/Home instead of just going to localhost:port/
This is my code:
RouteConfig:
public class RouteConfig
{
public static void RegisterRoute(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
route.MapRoute(
"Default",
"{controller}/{action}",
new {controller = "Home", action = "Index"}
);
}
}
This is the Area that is not being registered:
public class TransaccionesAreaRegistration : AreaRegistration
{
public override string AreaName
{
get{
return “Transacciones”;
}
}
public override void RegisterArea(AreaRegistrationContext context){
context.MapRoute(
"Transacciones_default",
"Transacciones/{controller}/{action}/{id}",
new { controller = "Transacciones", action = "Index", id = UrlParameter.Option}
);
}
}
Finally, this is my global.asax (I do call AreaRegistration.RegisterAllAreas() method):
protected void Application_Start(){
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
I will really appreciate some advice with this, I think I have spent enough time googling :O)
Just try this
RouteConfig:
public class RouteConfig
{
public static void RegisterRoute(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
route.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
This is the Area that is not being registered:
public class TransaccionesAreaRegistration : AreaRegistration
{
public override string AreaName
{
get{
return “Transacciones”;
}
}
public override void RegisterArea(AreaRegistrationContext context){
context.MapRoute(
“Transacciones_default”,
“Transacciones/{controller}/{action}/{id}”,
new { action = ”Index”, id = UrlParameter.Optional },
new string[] { "MyApp.Transacciones.Controllers" } // specify the new namespace
);
}
}
------------------------------OR Try This--------------------------------
public class RouteConfig
{
public static void RegisterRoute(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
AreaRegistration.RegisterAllAreas();
route.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Reason why default route is not working
Because you never registered a default one. Add this line in the RouteConfig -
routes.MapRoute("Home", "", new { Controller = "Home", Action = "Index" });
So the final code should look like this -
public class RouteConfig
{
public static void RegisterRoute(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")
routes.MapRoute("Home", "", new { Controller = "Home", Action = "Index" });
route.MapRoute(
"Default",
"{controller}/{action}",
new {controller = "Home", action = "Index"}
);
}
}
Possible reason why Area seems not working
May be the same reason also the Area registration seems not working. Try adding the following line in area registration -
routes.MapRoute("Transacciones_Home", "Transacciones", new { Controller = "Transacciones", Action = "Index" });
So it looks like -
public class TransaccionesAreaRegistration : AreaRegistration
{
public override string AreaName
{
get{
return “Transacciones”;
}
}
public override void RegisterArea(AreaRegistrationContext context){
routes.MapRoute("Transacciones_Home", "Transacciones", new { Controller = "Transacciones", Action = "Index" });
context.MapRoute(
“Transacciones_default”,
“Transacciones/{controller}/{action}/{id}”,
new { controller = “Transacciones”, action = ”Index”, id = UrlParameter.Option}
);
}
}
}
This questions was the one that helped me.
The thing is, the order in the routes' registration is very important. Considering that, I started checking my other areas registration, and I found out that all the requests where falling into the first rule that was a general rule like this:
routes.MapRoute(
name : "Default",
url : {controller}{action}{id}
);
So, after that rule, none of the rules were being considered.
Thanks everyone for trying to help, bests!
I have problem with routing. I have many pages on my site generated dynamically from database.
First thing which I want to accomplish is to route to these pages like that:
"How to repair a car"
www.EXAMPLE.com/How-to-repair-a-car
For now it works like that: www.EXAMPLE.com/Home/Index/How-to-repair-a-car
Secondly my default page have to be like that: www.EXAMPLE.com
On the Start Page will be news with pagging, so if someone click for instance in the "page 2" button, the address should looks: www.EXAMPLE.com/page =2
CONCLUSION:
default page -> www.EXAMPLE.com (with page = 0)
default page with specific page of news -> www.EXAMPLE.com/page=12
article page -> www.EXAMPLE.com/How-to-repair-car (without parameter 'page') routing sholud point to article or error404
PS: sorry for my english
Try to create route for articles in routing config, like this:
Routing config:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(null, "{article}",
new {controller = "Home", action = "Article" });
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
HomeController:
public class HomeController : Controller
{
public ActionResult Index(int? page)
{
var definedPage = page ?? 0;
ViewBag.page = "your page is " + definedPage;
return View();
}
public ActionResult Article(string article)
{
ViewBag.article = article;
return View();
}
}
/?page=10 - works
/How-to-repair-car - works
That approach excellent works.
Here is a basic routing example for www.example.com/How-to-repair-car
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace Tipser.Web
{
public class MyMvcApplication : HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute(
"ArticleRoute",
"{articleName}",
new { Controller = "Home", Action = "Index", articleName = UrlParameter.Optional },
new { userFriendlyURL = new ArticleConstraint() }
);
}
public class ArticleConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var articleName = values["articleName"] as string;
//determine if there is a valid article
if (there_is_there_any_article_matching(articleName))
return true;
return false;
}
}
}
}