I have a really weird one to me that I can't figure out. I'm not an expert with routing but this should be straight forward.
I have a controller called NewsletterController and it has the typical Index ActionResult. If I run my site in debug mode and use a link to go to my Newsletter section I get a 403.14 Forbidden message. If I add the "Index" to the route then it will go to the ActionResult just fine. I have other controllers setup with a Index ActionResult the exact same way and work just fine. It's something about this specific controller that is not working and I just don't see what the problem is.
This is my controller code:
public class NewsletterController : Controller
{
public ActionResult Index()
{
var vm = new NewsletterViewModel();
...CODE REMOVED FOR SPACE
return View(vm);
}
}
This is the action link from my _Layout.cshtml:
#Html.ActionLink("Newsletters", "Index", "Newsletter", null, new { #class = "nav-link" })
My Routing class
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 }
);
}
}
If I go here I get the 403.14 Forbidden message.
http://localhost:59571/Newsletter/
If I add the Index to the route it goes to the page.
http://localhost:59571/Newsletter/index
403.14 Forbidden typically occurs when you try to browse to a directory on the site and the Web site does not have the Directory Browsing feature enabled, and the default document is not configured.
In this case you have an actual Newsletter folder which is conflicting with the default route of the NewsletterController when you try to call
http://localhost:59571/Newsletter/
It will try to return the actual content of that folder which will fail if the feature is not enabled.
Either remove or rename the folder to something that does not conflict with any of your controller names
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.
I implemented a logout link in an ASP.NET MVC 5 application (C#), and it works perfectly with the current routing of my application:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Login", id = UrlParameter.Optional });
When I log in, I see the logout button and it works seamlessly.
However, I have other areas of the app that are designated for registered users (for which I have not considered the routing), and after going to an area designed for authorized users and I attempt to log out, I get the following path returned when the browser displays an error:
/Managers/Home/LogOff
I have a home controller with an action link of Logoff, but I'm uncertain how to represent my Managers folder (along with others on that level). And I could not find (and really, I have not searched exhaustively) readily available documentation of routing beyond what I implement in my routes.MapRoute file (seen above). I would appreciate it if someone can steer me in the right direction or tell me the correct pattern to use. I can't imagine the issue being anything other than routing. Thanks!
RouteConfig.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace HRCoreUS
{
using System.Web.UI.WebControls;
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Login", id = UrlParameter.Optional });
}
}
}
I see two options for you to define a route that suits you.
Fist one, if you want to log off all users from a specific folder, you can use a route like the following one. The keyword 'allusers' prevents you to have a conflict with your Default route. This also make your route more 'readable'.
config.Routes.MapHttpRoute(
"LogOffAllUserFromFolder",
"{controller}/{action}/allusers/{folder}",
new { controller = "Home", action = "Logoff", folder = RouteParameter.Optional });
This endpoint would then looks like :
/home/logoff/allusers/Managers
Second one, if you want to log off a specific user (for example user with id 124) from a 'Managers' folder, you can try the following route that won't conflict with Default since there are 4 arguments
config.Routes.MapHttpRoute(
"LogOffSpecificUserFromFolder",
"{controller}/{action}/{id}/{folder}",
new { controller = "Home", action = "Logoff", id = RouteParameter.Optional, folder = RouteParameter.Optional },
new { id = #"\d+" });
The endpoint would then looks like
/home/logoff/124/Managers
As you're id is an int I suppose, you can tell it by adding that to your route definition
new { id = #"\d+" }
And as {folder} is a string you don't need any other definition as it is the default type.
If I missunderstand your point, I hope this will gives you tips on how to declare MVC routes.
Take care.
If you want to use Attribute routing inside your Controllers folder Simply create a ManagersController
[RoutePrefix("managers")]
public class ManagerController
Then simply add a [Route("")] attribute on every function inside the controller.
Depending on any URL parameters you need define them in the Route attribute.
[HttpGet, Route("logoff}")]
public HttpResponseMessage LogOff() //route would be Managers/logoff
[HttpGet, Route("{id:int/view-profile}")]
public HttpResponseMessage ViewProfile(int id) //route would be Managers/4/view-profile
[HttpPost, Route("{id:guid/save-profile}")]
public HttpResponseMessage ViewProfile(Guid id) //route would be Managers/405750C8-0B3F-4EF2-A2A2-17A1EFBCDA39/save-profile
More info on attributes -
https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/
or for general catchall maproute in Routeconfig you would want something like this:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { action = "Index", id = UrlParameter.Optional }
);
Make sure this is the last route defined in your RouteConfig.
Then inside a ManagersController.cs create a
public HttpResponseMessage LogOff()
This Route would be localhost.com/managers/logoff
But from how I interpreted your question it seems as if your Authentication logic is tied to a specific controller (Home)? You should have all that logic encapsulated in something like a AuthenticationController which could handle your login / logoff logic. This way its not dependent on anything else and you could have a route like this:
routes.MapRoute(
name: "Authentication",
url: "authentication/{action}",
defaults: new { controller = "Authentication", action = "Index"}
);
with a Login / LogOff Function. These would route to /authentication/login and /authentication/logoff
My MVC application is set up with controllers at the root/global level. These have no explicit Area. I also have a single "Admin" area. URLs that begin with /admin/ are routed to the matching controller in the Admin area. Other URLs are routed to the matching global controller. This is working fine for the most part.
The issue I'm having is that in the case when a URL matches a controller in the Admin area when one of the same name doesn't exist on the global area, the request is incorrectly routed to the controller in Admin area. I know this is happening because I put a breakpoint on the matching action in the relevant controller.
For example, I have a controller called CalendarController in the Admin area. When I visit /admin/calendar, it works because it finds the action and the corresponding view in Areas/Admin/Views/Calendar/Index.cshtml. The problem occurs when I visit /calendar. I do not have a controller named Calendar at the root level, but for some reason it routes the request to the Admin area's CalendarController, which I don't want. I want it to return a 404 because no CalendarController exists at the root level. Instead, I get an error because it's searching for the view at the root level (at /Views/Calendar/Index.cshtml) even though the matching controller was in the Admin area.
How can I prevent the Admin area from being searched for matching controllers except when the URL has /admin in it?
Here's the relevant route code, which is basically stock except for the namespaces addition. The issue still happens without the namespace. There are more routes in the actual application, but I'm getting the same behavior in a brand new MVC project.
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 },
new[] { "AreaProblem.Areas.Admin.Controllers" }
);
}
}
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
What I mean by a controller at the "root level" is Controllers/HomeController in this screenshot. I want URLs that don't start with /admin to only look at those controllers. The problem is that it's also searching in Areas/Admin/Controllers.
So the MVC routing engine will look in different namespaces to try and find a matching controller. You can solve this by specifying a namespace (like you did for the admin area). You can also specify that a route not search other namespaces using DataTokens.
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new [] { "AreaProblem.Controllers" }
).DataTokens["UseNamespaceFallback"] = false;
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.
I am trying to find out why the routing of these two sittuations are not functioing. I want to conver this rout in the Routes.config file to a route attribute. It needs to be a default, because when you just load the site, without any url entered, it needs to hit /Home/Index action.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I added this to the Home controller for the actionResult Index(), but it didn't work. Said no document loaded.
[Route]
[Route("~/", Name = "default")]
public ActionResult Index()
{
var environmentsSharedAccounts = new List<EnvironmentSharedAccountVM>();
return View(environmentsSharedAccounts);
}
Why does this now not resolve. Thanks in advance. BTW. I am finding, that the books I have read, and the examples I have seen are seeming to be more compleicated to me then I thought I guess, because this routing has been giving me issues. I think I understand it, but it doesn't work how expected. Anyways....
Try
[Route("")]
public ActionResult Index()
....
Do you have this line on WebApiConfig.cs :
config.MapHttpAttributeRoutes();
?