I have a project with the following structure:
Solution
- CMS.core
---Areas
------Admin
---------Controllers
- Site.Web
---Areas
------Admin
---------Controllers
Everytime I try to route to a controller under site.web/areas/admin/controllers it appears to only look in cms.core/areas/admin/controllers.
Does this make sense? How do I route mvc to multiple areas of the same name located in different projects?
You need to provide the namespace in which the controller resides.. for example:
routes.MapRoute(
"SiteWebAdminRoute",
"site.web/areas/{controller}/{action}/{id}",
new { Area = "SiteWeb", controller = "Home", action = "Index", id = UrlParameter.Optional },
new string[] { "Site.Web.Areas.Admin.Controllers" });
..or something similar. Notice the string array down the bottom though. If you look in the Intellisense, it shows you that this string array represents any namespaces where this route should look for controllers. You can do the same with your other area route.. except you would provide a different namespace to look in.
Related
I'm putting together a simple enough brochure site and decided to use MVC3 as a learning opportunity. Content of certain sections of the website will be stored in a DB and can be updated by an admin via a simple GUI. I decided not to use a prebuilt CMS again to learn how to do database operations in this language which is new to me.
I want a very simple URL structure:
foo.com (home)
foo.com/bio
foo.com/news
foo.com/about
foo.com/events
etc
The straightforward way to achieve that is to have a controller for each page, and use the Index() ActionResult of each controller.
Is it OK / best practice to have a controller for each of these pages of the site? News and Events won't have subpages, but might have paging, with the URL looking something like
foo.com/news/
foo.com/news/page2
foo.com/news/page3
foo.com/news/page4
If I had a single controller, and used multiple actions, the URLs by default look like
foo.com (home)
foo.com/home/bio
foo.com/home/news
foo.com/home/about
foo.com/home/events
Which would then have me updating the routing to achieve what I want.
With respect to the use of controllers, I think the best practice is to have a particular controller for a domain of action or domain of content, not by the hierarchy of your main menu.
For example:
Your main page:
foo.com
Controller -> Home
Method -> Index
Parameter -> null
foo.com/news/2
Controller -> news
Method -> Index
Parameter -> 2
But Home and News are two different "equal" controllers, it just happens that the first controller the user interacts with is the Home controller.
In the case you want to use a single controller, you might try,
routes.MapRoute(
name: "Default",
url: "{action}/{page}",
defaults: new { controller = "Home", action = "Index", page = UrlParameter.Optional },
constraints: new { page = new PagingConstraint() }
);
as route defination. And to only allow paging for "news" and "events", use a custom route constraint as,
public class PagingConstraint : IRouteConstraint
{
private static readonly string[] PagingEnabledActions = new string[] { "news", "events" };
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return string.IsNullOrEmpty(values[parameterName].ToString()) || new Regex(#"^[Pp][Aa][Gg][Ee][0-9]+$", RegexOptions.Compiled).IsMatch(values[parameterName].ToString())
&& PagingEnabledActions.Contains(values["action"].ToString().ToLower());
}
}
Hope this helps.
Little help here and advice.
Working on my first MVC application and I've got an entity of Students setup.
Student Controller and views with basic CRUD capabilities.
mysite.com/Student gets me there.
Now I want to add Payments, so I've added a Payments controller and views with basic crud.
that gives me mysite.com/Payments
I want payments to go a URL that looks like: mysite.com/Student/Payments
So I researched URL routing and (I think) I had it backwards for a long time as nothing seemed to work. But now, I've created this additional Route:
routes.MapRoute(
"Payments",
"Student/Payments/{action}/{id}",
new { Controller = "Payments", action = "Index", id = UrlParameter.Optional }
);
And now it all seems to work properly. When I send an ActionLink to any action in the Payment controller, the URL is correct. For example: www.mysite.com/Student/Payments/Edit/5 comes up as the URL.
The problem I'm having is that Payments is still a base URL route. So I can also get to payments by going to www.mysite.com/Payments
How do I "remove" that route, so that mysite.com/Payments is not valid? Or am I doing this all ass-backwards in some way?
Any help appreciated.
Your kind of thinking about it the wring way around. The mapping configuration just supplies a hierachical list of rule to specify where a particular url's code lives.
So when you say it's still hitting mysite.com/Payments. That's because it's hitting the default rule in your Global.asax
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional} // Parameter defaults
);
You could remove this but then no default rules will work.
or you can add an ignore rule. In your case something like
routes.IgnoreRoute("Payments/{action}/{id}");
make sure you put this above the default rule.
You need to use overload of MapRoute method for your default route i.e.:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index" },
new { controller = ""}); //there constraints for controller goes
Look at this blog post about creating custom constraints, there is example for "not equals"
Im working my way though an ASP.NET MVC tutorial and couldnt find the answer im looking for.
I understand that each controller class in the 'Controller' root folder is mapped to a Url, so:
****Controller Folder****
|- StoreController.cs
Maps to $url/Store
However, If I wish to creater a 'subfolder'
I.e. a Controller class located for $url/Store/Testing I cant seem to see how I go about it.
I tried deriving a class from StoreController.cs, but that didnt work.
URLs do not necessarily correspond to MVC application internal folder structure. You can use MVC routing tables to conceal the internal structure and redirect specific URLs to any controllers/actions you want. For example, you can create a TestingController.cs class in the Controllers folder and use this route in Global.asax:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Store-Testing", // Route name
"Store/Testing/{action}/{id}", // URL with parameters
new { controller = "Testing", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
In this case, a request to http://[domain]/Store/Testing will be handled by TestingController.
That url would with the default route point to an action called Testing, within the Store controller.
You can however create your own custom routes in your global.asax file.
I have a MVC3 application with two areas and a root area. The general structure looks like
Root
- Root/Areas/Manager
* Views/Home/Index.cshtml
* ManagerAreaRegistration.cs
- Root/Areas/Participant
* Views/Home/Index.cshtml
* ParticipantAreaRegistraion.cs
- Root
* Views/Home/Index.cshtml
* Views/Account/Register.cshtml
* Global.asax.cs
I am having two problems with routing. The first is that I am unable to navigate to any pages in the Root/Views folders except the one set as default in the Global.asax.cs file. The Global.asax.cs file looks like:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new {controller="Home" , action = "Index", id = UrlParameter.Optional },
new[] { "MVCApplication.Controllers" } // for areas
);
...
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
...
And the code in Root/Views/Home/Index.cshtml which is the start page looks like:
#Html.ActionLink("Accounts","Register", new {area="", controller="Accounts"},null)
#Html.ActionLink("Manager", "Index", new { area = "Manager", controller = "Home" })
#Html.ActionLink("Participant", "Index", new { area = "Participant", controller = "Home" })
The two area links work fine as I have added routes into the registration files in each area, but the link to Accounts/Register which is another page in the root gives a 'resources not found error'. However, if I change the Global.asax.cs route to have
new {controller="Accounts" , action = "Register", id = UrlParameter.Optional },
in the default route, then I can start on the Register page.
So my first question is: How do I use routes to be able to access both pages in the Areas and in the Root (ie the Accounts/Register page)?
My second question has to do with the areas themselves. Since they both have a 'Home' controller, I have put the area name in front of one to distinguish it, but I would like to not have to do this. Currently the 'ParticipantAreaRegistration.cs file has the code:
context.MapRoute(
"Participant_default",
"Participant/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "MvcApplication.Areas.Participant.Controllers" } // for areas
);
which gives URL's of "localhost**/Participant/Home"
while the ManagerAreaRegistraion.cs has code
context.MapRoute(
"Manager_default",
"{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional },
new[] { "MvcApplication.Areas.Manager.Controllers" } // for areas
);
which gives URL's of "localhost***/Home/"
My second question is : How can I have the URL of "localhost**/Home for both Manager and Participant (or for any number of areas) without having to have the Area name displayed in the URL?
I know this question is similar to others already on file, but I have scoured these to no avail and am currently drowning in inefficiency, so I thought I would try asking with specificity. Thanks.
You can use custom routing.
Something similar to this one:
MVC 2 AreaRegistration Routes Order
Using the solution in the above problem, you can write custom order of routing.
In one of my application, I have areas named Admin,Blog,Members and
Public. I have routed the Public area as the url:
http://localhost:4000/, Admin as: http://localhost:4000/admin, blog
as: http://localhost:4000/blog, etc.. If you want my code, I can give
you.
In my ASP.NET MVC3 project, I have a folder called Content (the default folder for an MVC project). But I also have a controller called Content. And when I want to use the default actions of this controller, I simply use http://domain/content/, which is equivalent to http://domain/content/index. But IIS returns 403 error and thinks that I'm gonna get the directory list of the Content Folder. Well, this question is already discussed in this question. But I don't know how to rewrite my URL to append the default action to it. May someone help please.
You can get around this by changing routing configuration to specify:
routes.RouteExistingFiles = true;
You will then need to set up some ignore rules to prevent genuine static content being gobbled up by the routing engine.
For example, I have a folder called Touch in my app, and I also have a specific route for Touch. So the working config is:
routes.RouteExistingFiles = true;
routes.IgnoreRoute("Touch/Client/{*touchclientversion}", new { touchclientversion = #"(\d*)(/*)" });
I agree that this kind of thing should generally be avoided, but sometimes it's nice to have pretty URLs :-)
You can add a default route like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
In your case:
routes.MapRoute(
"DefaultContent", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Content", action = "Index", id = "" } // Parameter defaults
);