I have the following code for the navigation bar at the top of my application:
<li>#Html.ActionLink("Users", "Index", "Account")</li>
<li>#Html.ActionLink("Models", "Index", "Models")</li>
In AccountController I have the following Index function:
[Authorize(Roles = "Admin, CanEditGroup, CanEditUser")]
public ActionResult Index()
{
var users = _db.Users;
var model = new List<EditUserViewModel>();
foreach (var user in users)
{
var u = new EditUserViewModel(user);
model.Add(u);
}
return View(model);
}
In ModelsController I have the following Index function:
public ActionResult Index()
{
return View();
}
When I click on the 'Users' link I am taken to '/Account' and the Index is correctly shown. However, when I click the 'Models' link I am taken to '/Models' and receive a 'HTTP Error 403.14 - Forbidden' error. When I debug this I can see that the Index function in 'ModelsController' isn't being hit. '/Models/Index' works fine though.
It should be noted that I am using a template where AccountController already existed. I have since added ModelsController.
Finally, here is my simple routing file:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Please help me understand the difference between AccountController and ModelsController which is causing a difference in routing behaviour.
i think you already have a models folder or some other resource with named models in your project.
you can change your controller name.
or set RouteExistingFiles for your route collections
routes.RouteExistingFiles = true;
will help
Related
Fairly new to MVC, I would like the URLs of my article pages to be like this:-
http://www.example.com/article1
http://www.example.com/article2
http://www.example.com/article3
How can I set up the routing such that whenever someone types in the above it calls an action called article in the controller and passes the path to it?
I tried something like this but to no avail: -
routes.MapRoute(
name: "article",
url: "{article}",
defaults: new { controller = "Home", action = "article" }
);
One solution is to add multiple routes.
routes.MapRoute(
name: "article1",
url: "article1",
defaults: new { controller = "<YourControllerName>", action = "article1" }
);
routes.MapRoute(
name: "article2",
url: "article2",
defaults: new { controller = "<YourControllerName>", action = "article2" }
);
Edit:
From OP's comment, it is understood that there would be 'n' number of articles(urls). To deal with that, we can create a custom route handler.
Step 1: Create a new custom route handler inheriting from MvcRouteHandler
public class CustomRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var controller = requestContext.RouteData.Values["controller"].ToString();
requestContext.RouteData.Values["controller"] = "Home";
requestContext.RouteData.Values["action"] = "Index";
requestContext.RouteData.Values["articleId"] = controller;
return base.GetHttpHandler(requestContext);
}
}
Step 2: Register the new route. Make sure to add this route before default route.
routes.Add("Article", new Route("{controller}", new CustomRouteHandler()));
In the given CustomRouteHandler class, the Controller and Action is hard coded with "Home" and "Index" respectively. You can change that to your own controller and action name. Also you would see a "articleId" setting to RouteData.Values. With that setting, you would get the articleId as a parameter in your Action method.
public ActionResult Index(string articleId)
{
return View();
}
After all the changes, for the url http://www.example.com/article1, the Index() method of HomeController gets invoked with articleId set to 'article1'.
Similarly for http://www.example.com/article2, the Index() method gets invoked with parameter articleId set to 'article2'.
I use VS2013 and created MVC application by wizard. I also deleted all extra files and have the following:
1) RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
}
2) HomeController.cs
public class HomeController : Controller
{
[Route("Home/Index")]
public ActionResult Index()
{
return View();
}
}
3) Index.cshtml
#{
ViewBag.Title = "Home Page";
}
Home page
I've got the page with error:
HTTP 403.14 - Forbidden
But, if I add to URL in browser's address bar manually - Home/Index:
http://localhost:50600/Home/Index
The page appears.
What I'm doing wrong?
Remove the "Home" from the route as the controller name HomeController is already starting your route with "Home". If you want to change that "Home" prefix, you can add an attribute to the HomeController class to define that.
Also, the default route name for an action will match the action name, so in this case you could use [Route("")] and the url /Home/Index would work.
My guess is that when you try this url:
http://localhost:50600
It does not work because you have removed the default route from your routes config. I don't know if you removed it yourself, but RoutesConfig.cs file usually comes with the following default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
This code ensures that if the user does not provide the controller or the action the site will default to index action of the home controller (you ca see that under the defaults parameter). This would also explain why it works when you try this route:
http://localhost:50600/Home/Index.
I think I know what's your problem now. You're expecting the default url to show up your Index View in HomeController but you've not setup the default route. You can set the default route by adding the following lines in your RouteConfig.cs
config.Routes.MapRoute(
name: "Default",
routeTemplate: "{controller}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
Alternatively, if you wish to use attribute routing only without mixing with route template, you can just add the default route as following:-
config.Routes.MapRoute(
name: "Index",
url: "",
defaults : new { controller = "Home", action = "Index" }
);
I'm building an intranet where I have the following home controller:
[Route("{action=index}")]
public class HomeController : Controller
{
public ActionResult Index()
{
return View(HomeModelBuilder.BuildHomeModel());
}
public ActionResult FormsHome()
{
return View(HomeModelBuilder.BuildFormsHomeModel());
}
}
I'm trying to get my forms homepage to have a url of http://intranet/forms so I thought I could do this using the following routing attribute:
[Route("~/forms")] // have also tried 'forms' and '/forms'
public ActionResult FormsHome()
but when I go to the url, it complains that multiple controllers have that route:
The request has found the following matching controller types:
HRWebForms.Website.Controllers.ChangeDetailsController
HRWebForms.Website.Controllers.InternalTransferController
HRWebForms.Website.Controllers.LeaverController
...
I have also tried adding [RoutePrefix("")] to the controller but this didn't work either
Is there a way to give that action a url of "forms" (without any controller or without adding a separate forms controller with an index) by just using routing attributes?
You could try adding [RoutePrefix("forms")] to your controller, but this will result in all your actions expecting the same prefix.
There is a walkaround for this too (by using [Route("~/RouteParam/AnotherRouteParam")] to have Route "RouteParam/AnotherRouteParam") but it seems to me that FormsController would cost less work.
Ok so ranquild's comment pushed me in the right direction. In my route config, I had the default route of
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
So that my homepage would still work on the url with nothing in. If I changed this to
// Needed for homepage
routes.MapRoute(
name: "Home",
url: "",
defaults: new { controller = "Home", action = "Index" }
);
// Needed for Html.ActionLink to work
routes.MapRoute(
name: "Default",
url: "{controller}/{action}",
defaults: new { controller = UrlParameter.Optional, action = UrlParameter.Optional }
);
It seemed to solve the problem
I have an asp.net MVC site and i would like to go to a controller without an action, but i would also like to be able to give an action on the same or other controllers.
So lets say i have Page.
I would like to be able to access the following urls
MY_URL (nothing else) - This would get another page with id = 1, or name = Home (business logic doesnt matter)
MY_URL/Page/id - This will get a page with a particular Id
MY_URL/Page/Create - Create a new page
MY_URL/Page/Delete - Delete a page
MY_URL/Page/Edit - Edit a page
I thought this would do it, but Create/Delete/Edit dont work (they just go to MY_URL/page with no id)
routes.MapRoute(
name: "PageWithId",
url: "Page/{id}",
defaults: new { controller = "Page", action = "Index" }
);
routes.MapRoute(
name: "default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Page", action = "Index", id = UrlParameter.Optional }
);
Here is my controller
public class PageController : Controller
{
private PageService _service;
public PageController(PageService service)
{
_service = service;
}
public async Task<ActionResult> Index(int? id)
{
... code to get page if id <> null
... code to get home page id id = null
// return view
return View(model);
}
public ActionResult Create()
{
return View();
}
... Delete, Edit methods implemented
}
Any help would be appreciated
What my requirement is;
if I type www.mysite.com - it will load the front page.
But if I type www.mysite.com/john - it will return john's profile page.
John's profile is originally located in /Profile/John and this works fine. But the requirement is www.mysite.dom/John.
I am trying many ways with NO success. Would be nice if anyone can help me out.
cheers
Define two routes.
First to "/Profile/{name}", then to "/{name}", pointing to the same action.
If you want to use the same controller and have routes setup to respond to parameters, you can setup your routes like this too
routes.MapRoute(
name: "Meeting",
url: "{name}",
defaults: new
{
controller = "Home",
action = "Welcome"
}
);
routes.MapRoute(
name: "Default",
url:"",
defaults: new
{
controller = "Home",
action = "Index"
}
);
My HomeController looks like
public void Welcome(string name)
{
ViewBag.Title = "Home Page";
}
public ActionResult Index()
{
return View();
}