I'm trying out ASP.NET MVC, but, after reading a huge tutorial, I'm slightly confused. I understand how Controllers have Actions that URLs are routed to, but how do home pages work? Is the home page its own controller (e.g. "Home") that has no actions? This sounds correct, but how is it functionality implemented without Actions (no Actions means no methods that call the View Engine)?
In other words, my question is this: how are home pages implemented (in terms of Controllers and Views)? Could you please provide sample code?
"Home" page is nothing more than arbitrary Action in a specific Controller which returns a certain View
To set the "Home", page, or better worded, the default page, you need to change the routing info in the Global.asax.cs file:
public class MvcApplication : System.Web.HttpApplication
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
AreaRegistration.RegisterAllAreas();
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "NotHome", action = "NotIndex", id = "" } // Parameter defaults
);
Notice the route definition:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "NotHome", action = "NotIndex", id = "" } // Parameter defaults
);
This route is a "catch-all" route, meaning it will take any URL and break it down to a specific controller and action and id. If none or one of the routes are defined, it will use the defaults:
new { controller = "NotHome", action = "NotIndex", id = "" }
This says "If someone visits my application, but didn't specify the controller or action, I'm going to redirect them to the NotIndex action of my NotHome controller". I purposly put "Not" to illustrate that naming conventions of "Default.aspx", "Index.html" don't apply to MVC routes.
The home page would usually equate to the default action/view on the default controller.
So you'd create, for example, a HomeController with an Index action and a corresponding view, then in your route mappings you'd create a default, catch-all route, something like this:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" });
It depends on what you mean by "home page". If you mean the page seen when you go to http://www.yoursite.com (with no page or Controller name) then that is the Index controller, which works like any other except you don't see the name of the controller in the URL.
Related
I have an MVC project using C#.
I have been using only one view, Views/Home/Index.cshtml to do most of the stuff I need the app to do.
Today I was asked to add a new page, that will serve as an "Admin" type of page to allow some basic crud operations to a record.
I am having trouble understanding how to navigate to a page other than the Home/Index.cshtml, actualy I do not even navigate to that page in the browser, since that is the default routing, the url looks like: http://localhost:51225/Meetings/Agenda/ -- this is how I can see the Index.cshtml page.
So far what I have done, in the HomeController, I added this code below the Index View:
// GET: Home
public ActionResult Index()
{
return View();
}
//GET: Admin
public ActionResult Admin()
{
return View(); -- I right clicked, and added a new view named "Admin"
}
My folders now look:
Views
Home
Admin.cshtml
Index.cshtml
I have not changed the RouteConfig class:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
}
}
I can still open my app, and see the Index.cshtml when I go to:
http://localhost:51225/Meetings/Agenda
But I do not know how to access the Admin.cshtml
So far I know it is not by simply adding Admin at the end
http://localhost:51225/Meetings/Agenda/Admin
Nor
http://localhost:51225/Meetings/Agenda/Home/Admin
Nor
http://localhost:51225/Meetings/Agenda/Home/Admin.cshtml
Is it possible to ask for help in trying to learn how and what needs to chane in my solution in order to navigate to a different page that Index in the Home folder?
Add Custom route to the RegisterRoutes method in Route confige before default route:
routes.MapRoute(
name: "AgendaRoute",
url: "Meetings/Agenda/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Final RouteConfig:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "AgendaRoute",
url: "Meetings/Agenda/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
Result :
http://localhost:51225/Meetings/Agenda => Index.html
http://localhost:51225/Meetings/Agenda/index => Index.html
http://localhost:51225/Meetings/Agenda/index/1 => Index.html
http://localhost:51225/Meetings/Agenda/admin => Admin.html
http://localhost:51225/Meetings/Agenda/admin/1 => Admin.html
the default routing convention of ASP.NET MVC is Controllername/Action/parameter.
Lets say for example you have a Route like Products/Create, ASP.NET will search for an Action named Create in ProductsController and the view will be Create.cshtml inside the Products directory.
I suggest you follow that convention and create an AdminController and put Index action on the controller. Which you can Access by localhost:51225/Admin/Index. For the views, the convention is it searches for a view with the same name as the action,, that is you create a folder named Admin and put Index.cshtml inside it
You can always access anything by /ControllerName/ViewName/ParametersIfNeeded. I suggest you to add a button on the navigation bar which will be visible only for admins, and so that only they can visit that page. In your case the admin View can be accessed with http://localhost:51225/Home/Admin.
This question already has answers here:
Routing in ASP.NET MVC, showing username in URL
(2 answers)
Closed 4 years ago.
I am new to C# MVC,
This is my default RouteConfig File,
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 }
);
}
}
When I run my project http://localhost:50382 it redirects the default home index method.
How can I build custom url like http://localhost:50382/somestringcode and call a specific ActionMethod. Something Like a custom route that points to specific ActionMethod and the stringcode will be passed as parameter.
public ActionResult Method1( string code)
{
return View();
}
What you are searching for is attribute routing. That means specifying URL routes explicitly.
First, you need to enable it
routes.MapMvcAttributeRoutes();
Then add Route attribute to desired action:
[Route("")]
public ActionResult Method1( string code)
{
return View();
}
Since code parameter is simple type, it will be searched in request URL.
You need to do something like this, where controller1 is the controller name that contains Method1, and make sure you place this first, and leave the original route config, so when it doesn't match this route, it will use default route.
Please note this is bad practice, and it will fail in case route is trying to access default action for a controller "Index" as #stephen mentioned in the comments below, and that's why I would suggest adding a prefix ex "Action1" to the route.
routes.MapRoute
(
name: "Method1",
url: "Action1/{code}",
defaults: new { controller = "controller1", action = "Method1", code = "default"}
);
I have a controller called "StuffController" with a parameterless Index action. I want this action to be called from a URL in the form mysite.com/stuff
My controller is defined as
public class StuffController : BaseController
{
public ActionResult Index()
{
// Return list of Stuff
}
}
I added a custom route so the routes are defined like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Custom route to show index
routes.MapRoute(
name: "StuffList",
url: "Stuff",
defaults: new { controller = "Stuff", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
But when I try to browse to mysite.com/stuff I get an error
HTTP Error 403.14 - Forbidden
The Web server is configured to not list the contents of this directory.
The URL mysite.com/stuff/index works fine. What I am doing wrong?
HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this directory.
The error indicates that you have a virtual directory (probably a physical one) in your project called /Stuff. By default, IIS will first reach this directory and look for a default page (for example /index.html), and if no default page exists will attempt to list the contents of the directory (which requires a configuration setting).
This all happens before IIS passes the call to .NET routing, so having a directory with the name /Stuff is causing your application not to function correctly. You need to either delete the directory named /Stuff or use a different name for your route.
And as others have mentioned, the default route covers this scenario so there is no need for a custom route in this case.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Passing the URL `/Stuff` will match this route and cause it
// to look for a controller named `StuffController` with action named `Index`.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
It seems that your scenario is covered fine by default route, so there is no need for a custom Stuff one.
As to why the error is thrown, the fact that action is listed in defaults does not mean that it is actually becoming a part of a route. It should be mentioned in the route, otherwise it appears as there is no action at all. So what I think happens here is that first route is matched, but it cannot be processed as there is no action specified, so MVC passes request on to IIS, which throws the named error.
The fix would be simple:
// Custom route to show index
routes.MapRoute(
name: "StuffList",
url: "Stuff/{action}",
defaults: new { controller = "Stuff", action = "Index" }
);
But again, you shouldn't need that at all.
So I know google can penalize a site if you have the same content on multiple urls... unfortunately, in MVC this is too common i can have example.com/, example.com/Home/ and example.com/Home/Index and all three urls would take me to the same page... so how do I make sure that whenever Index is in the url, that it redirects to the same without the Index and of course the same thing with the Home
Perhaps this little library may be useful for you.
This library is not very convinient in your case, but it should work.
var route = routes.MapRoute(name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
routes.Redirect(r => r.MapRoute("home_index", "/home/index")).To(route);
routes.Redirect(r => r.MapRoute("home", "/home")).To(route);
The way I handle this is for default pages like Index is to simply create an explicit route for only one of them. I.e. "example.com/People" would be the route for People/Index, and there would be no valid page at the url "/example.com/People/Index".
The Home example is unique in that it has potentially three different URLs. Again in this case I'd simply create a route for "example.com" for that Index action, and not support the other two urls. In other words, you would never link to the other forms of the URL, so their absence should never cause a problem.
We use a Nuget package called AttributeRouting to support this. When you specifiy a GET route for a page, it overrides the defaults for MVC.
Using AttributeRouting usually you'd map the index to [GET("")] but for the special case of Home where you also want to also support the root URL that omits the controller name , I think you'd also add an additional attribute with IsAbsoluteUrl:
public class HomeController : BaseController
{
[GET("")]
[GET("", IsAbsoluteUrl = true)]
public ActionResult Index()
{...
So I found a way to do it without any external Library...
In my RouteConfig I had to add these two routes at the top, just below the IgnoreRoute
routes.MapRoute(
"Root",
"Home/",
new { controller = "Redirect", action = "Home" }
);
routes.MapRoute(
"Index",
"{action}/Index",
new { controller = "Redirect", action = "Home" }
);
Then I had to create a new Controller called Redirect and I created a method for each of my other Controllers like this:
public class RedirectController : Controller
{
public ActionResult Home()
{
return RedirectPermanent("~/");
}
public ActionResult News()
{
return RedirectPermanent("~/News/");
}
public ActionResult ContactUs()
{
return RedirectPermanent("~/ContactUs/");
}
// A method for each of my Controllers
}
That's it, now my site looks legit. No more Home, no more Index in my URLs, this of course has the limitation of not being able to accept parameters to any of the Index methods of your Controllers though if it was really necessary, you should be able to tweak this to achieve what you want.
Just an FYI, if you want to pass an argument to your Index Action, then you can add a third route like this:
routes.MapRoute(
name: "ContactUs",
url: "ContactUs/{id}/{action}",
defaults: new { controller = "ContactUs", action = "Index", id = UrlParameter.Optional }
);
This will create a URL like this: /ContactUs/14
I'm new to MVC (and ASP.Net routing). I'm trying to map *.aspx to a controller called PageController.
routes.MapRoute(
"Page",
"{name}.aspx",
new { controller = "Page", action = "Index", id = "" }
);
Wouldn't the code above map *.aspx to PageController? When I run this and type in any .aspx page I get the following error:
The controller for path '/Page.aspx' could not be found or it does not implement the IController interface.
Parameter name: controllerType
Is there something I'm not doing here?
I just answered my own question. I had
the routes backwards (Default was
above page).
Yeah, you have to put all custom routes above the Default route.
So this brings up the next question...
how does the "Default" route match (I
assume they use regular expressions
here) the "Page" route?
The Default route matches based on what we call Convention over Configuration. Scott Guthrie explains it well in his first blog post on ASP.NET MVC. I recommend that you read through it and also his other posts. Keep in mind that these were posted based on the first CTP and the framework has changed. You can also find web cast on ASP.NET MVC on the asp.net site by Scott Hanselman.
http://weblogs.asp.net/scottgu/archive/2007/11/13/asp-net-mvc-framework-part-1.aspx
http://www.asp.net/MVC/
I just answered my own question. I had the routes backwards (Default was above page). Below is the correct order. So this brings up the next question... how does the "Default" route match (I assume they use regular expressions here) the "Page" route?
routes.MapRoute(
"Page",
"{Name}.aspx",
new { controller = "Page", action = "Display", id = "" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
On one of Rob Conery's MVC Storefront screencasts, he encounters this exact issue. It's at around the 23 minute mark if you're interested.
Not sure how your controller looks, the error seems to be pointing to the fact that it can't find the controller. Did you inherit off of Controller after creating the PageController class? Is the PageController located in the Controllers directory?
Here is my route in the Global.asax.cs
routes.MapRoute(
"Page",
"{Page}.aspx",
new { controller = "Page", action = "Index", id = "" }
);
Here is my controller, which is located in the Controllers folder:
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
public class PageController : Controller
{
public void Index()
{
Response.Write("Page.aspx content.");
}
}
}
public class AspxRouteConstraint : IRouteConstraint
{
#region IRouteConstraint Members
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return values["aspx"].ToString().EndsWith(".aspx");
}
#endregion
}
register the route for all aspx
routes.MapRoute("all",
"{*aspx}",//catch all url
new { Controller = "Page", Action = "index" },
new AspxRouteConstraint() //return true when the url is end with ".aspx"
);
And you can test the routes by MvcRouteVisualizer