I have 2 areas in my project:
Areas | Admin
Areas | FrontEnd
What I would like is when I visit the site, the default route should load Controllers / Views / Models from the FrontEnd area. It's normal to have Url/Admin for an admin panel but I would rather not have to force Url/FrontEnd (or some other variation). Basically I don't want to use the Controller / Model / View folders on the root level.
I'm not sure how to change the code to allow this or even it's an advisable method. Could someone provide some guidance please?
What I have:
routes.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new {
area = "Admin",
controller = "Home",
action = "Index",
id = UrlParameter.Optional
},
namespaces: new[] { "WebsiteEngine.Areas.Admin.Controllers" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {
area = "FrontEnd",
controller = "Home",
action = "Index",
id = UrlParameter.Optional
},
namespaces: new[] { "WebsiteEngine.Areas.FrontEnd.Controllers" }
);
However this produces an error:
The view 'Index' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/Home/Index.aspx
~/Views/Home/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx
~/Views/Home/Index.cshtml
~/Views/Home/Index.vbhtml
~/Views/Shared/Index.cshtml
~/Views/Shared/Index.vbhtml
I do have views available in the areas and this doesn't look like it's looking there.
I believe you can just do something like this:
// Areas/Admin/AdminAreaRegistration.cs
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "Admin"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "Admin_Default",
url: "Admin/{controller}/{action}/{id}",
defaults: new
{
area = "Admin",
controller = "Home",
action = "Index",
id = UrlParameter.Optional
});
}
}
// Areas/Admin/FrontEndAreaRegistration.cs
public class FrontEndAreaRegistration : AreaRegistration
{
public override string AreaName
{
get { return "FrontEnd"; }
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "FrontEnd_Default",
url: "{controller}/{action}/{id}",
defaults: new
{
area = "FrontEnd",
controller = "Home",
action = "Index",
id = UrlParameter.Optional
});
}
}
// Global.asax.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
...
}
Now, in your RouteConfig class, you probably have a Default route set up. Bear in mind that as long as you call AreaRegistration.RegisterAllAreas before you call RouteConfig.RegisterRoutes, the routes that you set up in the areas may override the routes you set up in RouteConfig. (Routes are evaluated in the order they appear in the Routes collection, and .MapRoute pushes new routes to the end)
Related
I have an area name HR. here is the HRAreaRegistration.CS
namespace WebApplication1.Areas.HR
{
public class HRAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "HR";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"HR_default2",
"HR/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
context.MapRoute(
"HR_default1",
"{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
}
}
in RouteConfig.cs
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 = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "WebApplication1.Controllers" }
);
}
}
I was hoping that since I prioritized the main controller namespace when I go to Home/Index I would hit the view and controller HomeController/Index. Instead I am going to the Home Controller in the HR Area. HR/HomeController/Index. not sure what I am doing wrong.
here is home controller (the one I would like to hit when I go to Home/Index)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace WebApplication1.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
and here is the home controller in the hr area (the one I am hitting when I go to Home/Index even though I shouldn't be)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace WebApplication1.Areas.HR.Controllers
{
public class HomeController : Controller
{
// GET: HR/Home
public ActionResult Index()
{
return View();
}
}
}
/***********Editing my question in response to pfx answer********************/
for this application if a certain variable is set then the default page should be in the HR area. specifically HR area Controller OST action Index. so all of the following should take us to that view.
http://nrdephrs01/hrpa
http://nrdephrs01/hrpa/ost
http://nrdephrs01/hrpa/ost/index
http://nrdephrs01/hrpa/hr/ost/
http://nrdephrs01/hrpa/hr/ost/index
now when they get to this default page there is a link that is to take them to Users/Details/1524 so this controller is not in an area. it is just Controller = Users Action = Details.
here are my routes which work until I try to go to the Users/Details/1524 where it can not find the controller.
HRAreaRegistration
namespace Portal.UI.Areas.HR
{
using System.Web.Mvc;
public class HRAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "HR";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"HR_default",
"HR/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
// if the application is Out of State travel there will be an appsetting called OST set to true.
// for OST applications have the main default page be HR/OST/Index
string ost = System.Configuration.ConfigurationManager.AppSettings["OST"];
if (ost == "true")
{
context.MapRoute(
"Details",
"Users/{action}/{id}",
new { controller = "Users", action = "Index", id = UrlParameter.Optional });
context.MapRoute(
"HR_default1",
"{controller}/{action}/{id}",
new { controller = "OST", action = "Index", id = UrlParameter.Optional });
}
}
}
}
and here is RouteConfig.cs
{
using System.Web.Mvc;
using System.Web.Routing;
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 = "Home", action = "Index", id = UrlParameter.Optional });
}
}
}
From the comments I read that you want http://localhost:50908/HRHome/Index to be handled by the HRHomeControllerin the HR area.
To do so you have to define an explicit route in HRAreaRegistration.cs for HRHome, replacing {controller} with HRHome in the route template.
Having this route with an explicit and unique route template eliminates any conflicts with other routes, including those from the default area.
It is important to register this route from within the AreaRegistration instead of RouteConfig, otherwise the views don't get resolved from the appropriate views folder within the HR area.
context.MapRoute(
name: "HRHome"
url: "HRHome/{action}/{id}",
defaults: new {
controller = "HRHome",
action = "Index",
id = UrlParameter.Optional
},
namespaces: new [] { "WebApplication1.Areas.HR.Controllers" }
);
The full area registration looks like:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "HRHome"
url: "HRHome/{action}/{id}",
defaults: new {
controller = "HRHome",
action = "Index",
id = UrlParameter.Optional
},
namespaces: new [] { "WebApplication1.Areas.HR.Controllers" }
);
context.MapRoute(
name: "HR_default"
url: "HR/{controller}/{action}/{id}",,
defaults: new {
controller = "HRHome",
action = "Index",
id = UrlParameter.Optional
},
namespaces: new [] { "WebApplication1.Areas.HR.Controllers" }
);
}
I have an MVC5 application using ASP Identity 2 and Fluentsecurity with the following methods in the Home controller which handle the log in page and logging out:
public ActionResult Login(string returnUrl)
{
this.ViewBag.ReturnUrl = returnUrl;
return this.View();
}
public ActionResult LogOff()
{
this.AuthenticationManager.SignOut();
return this.RedirectToAction("Login", "Home");
}
This works absolutely fine.
I now need to add an area into my application and set up routing accordingly. I have added a sub folder called 'Admin' under the 'Areas' folder and placed the relevant controllers and views in there in the appropriate subfolders.
I have then set up the routing as follows in Global.asax:
private static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "AppName.Web.Controllers " });
routes.MapRoute(
"Admin",
"Admin/{controller}/{action}/{querydata}",
new { querydata = UrlParameter.Optional },
new[] { "AppName.Web.Areas.Admin.Controllers" });
}
Which is then called as below:
private void Application_Start(object sender, EventArgs e)
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
SecurityConfigurator.Configure(SecurityConfig.Configure);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
FilterConfig.RegisterGlobalApiFilters(GlobalConfiguration.Configuration.Filters);
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.DefaultNamespaces.Add("AppName.Web.Areas.Admin.Controllers");
}
If i then run the application, routing is working as expected in my area and the main application, apart from it seems to have broken the Login and LogOff methods in the aforementioned Home controller, now giving a 404 error when trying to access them. The index method of the same Home controller works fine though.
In case it's related to Fluentsecurity, this is how security is configured:
internal static void Configure(ConfigurationExpression configuration)
{
configuration.GetAuthenticationStatusFrom(() => HttpContext.Current.User.Identity.IsAuthenticated);
configuration.GetRolesFrom(GetRoles);
configuration.For<HomeController>(x => x.Login(default(string))).DenyAuthenticatedAccess();
configuration.For<HomeController>(x => x.Index()).DenyAnonymousAccess();
configuration.For<HomeController>(x => x.LogOff()).AllowAny();
//Admin Home
configuration.For<Areas.Admin.Controllers.HomeController>(x => x.Index()).DenyAnonymousAccess();
}
Any ideas where I may be going wrong?
private static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Admin",
"Admin/{controller}/{action}/{querydata}",
new { querydata = UrlParameter.Optional },
new[] { "AppName.Web.Areas.Admin.Controllers" });
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "AppName.Web.Controllers " });
}
So I built a new ASP.NET MVC4 application, some really simple stuff. I added an Area for administration purposes. Everything works fine when I debug on Visual Studio's IIS Express.
The problem comes when I deploy this application on a Windows Server 2012's IIS, most of the time, when I try to acces my Area I get a 404 error. The weired thing is sometimes, after redeploying the application (but not changing anything), the area will work for a certain amount of time (until the application pool gets recycled maybe ?)
Anyway this is really weired and I'd need a hand on this. Here's what I've done :
Here is my RouteConfig for the base application :
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "NewsFilter",
url: "Articles/{tagName}",
defaults: new { controller = "Home", action = "Index", tagName = UrlParameter.Optional },
namespaces: new[] { "myapp.Controllers" }
);
routes.MapRoute(
"ViewArticle",
"Article/{articleId}/{articleTitle}",
new { controller = "Article", action = "Index", articleTitle = UrlParameter.Optional },
new { articleId = #"\d+" },
namespaces: new[] { "myapp.Controllers" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "myapp.Controllers" }
);
}
}
Now here's my AdminAreaRegistration for the Admin area
public class AdminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "Admin";
}
}
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
name: "Admin_default",
url: "Admin/Home/{action}/{id}",
defaults: new { controller="Home", action = "Index", id = UrlParameter.Optional },
namespaces: new []{ "myapp.Areas.Admin.Controllers" }
);
context.MapRoute(
name: "Admin_news",
url: "Admin/News/{action}/{id}",
defaults: new { controller="News", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "myapp.Areas.Admin.Controllers" }
);
context.MapRoute(
name: "Admin_Tags",
url: "Admin/Tags/{action}/{id}",
defaults: new { controller = "Tags", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "myapp.Areas.Admin.Controllers" }
);
}
}
Now here id the Application_Start method from Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); //This registers the admin Area
WebApiConfig.Register(GlobalConfiguration.Configuration); //I did not delete WebApiConfig even though I'm not using it
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes); //And here are my "normal" routes
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
All the controllers from my Admin area are in the namespace myapp.Areas.Admin.Controllers. The main app controllers are in the namespace myapp.Controllers.
On IIS, the app pool for the application is running in .net 4.0 Integrated mode.
Any idea why the area is working in debug mode, working sometimes on IIS and returning 404 most of the time ?
I have a front page and a CMS area with the following routes:
Default Front Page route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "SiteFactory.Site.Controllers" }
Administration route
context.MapRoute(
"Administration_default",
"administration/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I would like to route from my ContentController (inside the administration area) to the front page HomeController, like this:
[HttpPost]
[ValidateInput(false)]
public ActionResult Save(string content, string contentId, string pageId)
{
if (ModelState.IsValid)
{
//TODO: save content.
}
return RedirectToRoute("Default");
}
How can i do this?
just return RidirectToAction("Index", "Home");
class HomeController
{
public ActionResult Search(int[] sections, int categories)
{
return View();
}
}
i need url like
website.com/search/1,2,3/5
What route map should i use?
At present RegisterRoutes looks
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
use something like:
var ints = new int[] {1, 2, 3, 4, 5};
var result = string.Join(",", ints.Select(x => x.ToString()).ToArray());
to build the commaseparated string, and pass it in the route "Search/{csv}/{somevalue}"
I'd change the controller definition to handle the array:
public ActionResult Search(string sections, int categories)
{
// sectionsArray is int[].
var sectionsArray = sections.Split(',').Select(x => int.Parse(x)).ToArray();
return View();
}
then you can define the routing as usual: Home/{sections}/{categories}:
routes.MapRoute(
"Search", // Route name
"{Home}/{sections}/{categories}", // URL with parameters
new { controller = "Home", action = "Search" } // Parameter defaults
);
Notice that you have to add this on top of the default one.
Add search route, don't replace default one
Since you'll probably still be using default route with controller/action combination I suggest you do this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Search",
"search/{sections}/{section}", // rename these variables to what they actually are
new { controller = "Search", action = "Sections", sections = UrlParameter.Optional, section = UrlParameter.Optinal }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
But since it's hard to tell what requirements you're after here, maybe you're trying to use catch-all route parameter but not at the end of your URL request. If that's the case, you can check my code in blog post of such Route class that allows catch-all section anywhere in the URL and not just at the end as it is by default.