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
Related
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 am using MVC 4 and need to remove /Home/ folder from address bar...
Eg:
http://localhost:61700/Home/AboutUs
Need to be changed as...
http://localhost:61700/AboutUs
I did that by changing the default controller 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}",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
The above code is working as expected. I do have another folders as
brand, admin etc... here I want to show the url as
http://localhost:61700/brand/productInfo ... But I am getting server
error here as Server Error in '/' Application.
Can somebody suggest me, where am I doing wrong?
Screenshots here for more info:
This is your current RouteConfig.cs configuration:
routes.MapRoute(
name: "Default",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
You're telling Asp.net, when a request arrives, assume the first parameter as the action and the second parameter as the id. Right now you're not telling Asp.net to parse any parameter as the controller. Because of this it uses the default value (given as the third parameter of the MapRoute method) which is in this case Home.
In that case when parsing the request http://localhost:61700/AboutUs the values end up being:
controller: Home (it uses the default controller)
action: AboutUs (from the first parameter)
id: null (this doesn't matter right now)
When parsing the request http://localhost:61700/brand/productInfo the values end up being:
controller: Home (it uses the default controller because you haven't specified where to get the controller name from)
action: Brand (from the first parameter)
id: "productInfo"
The error you're getting is because there isn't a Brand action method in HomeController.cs with a parameter of type string named id.
Asp.net processes incoming requests by trying to match with the routes configured and it uses the first route that matches.
There are several ways to achieve what you want, which include but are not limited to:
Manually mapping every action in your HomeController.cs (choosing this method will depend on the amount of actions in your HomeController). This would look like:
routes.MapRoute(
name: "AboutUs",
url: "AboutUs",
defaults: new { controller = "Home", action = "AboutUs" }
);
routes.MapRoute(
name: "ContactUs",
url: "ContactUs",
defaults: new {controller = "Home", action = "ContactUs" }
);
// etc...
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Note how the default route is the last one, this is important because it is less specific than the others and if put before would match the request and want to look for an AboutUsController.
You could use route constraints. This would look like:
route.MapRoute(
name: "HomeControllerRoutes",
url: "{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { action = "AboutUs|ContactUs|etc..." } //Here you would put all your action methods from home controller that you want to accces as /{action}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
If you want to read more about route constraints, I found this article that explains that the constrains parameter can receive a regular expression (I suggest you modify the regular expression above to make it case insensitive) or an IRouteConstraint.
Update:
I just read your comment about having 160+ actions in your HomeController that would make your regular expression in my second suggestion quite long. In that case the other options you have could be:
Using a regular expression that rejects all other controller names, but that would violate the open/closed principle (OCP) and every time you add another controller you would have to add it to the regular expression.
Create the regular expression from the metadata of you HomeController class. This would look like
string.Join("|", typeof(HomeController).GetMethods().Select(info => info.Name))
Or you could take a look at IRouteConstraint to see if you could figure out a more elegant solution.
I have no experience with IRouteConstraint
Add this in your route.config / glibal.asax and don't change your default routes. Add following above it.
routes.MapRoute(
name: "About",
url: "AboutUs",
defaults: new { controller = "Home", action = "AboutUs" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I have 160+ views in the home controller
You don't mention how many views you have in the other controllers, nor how complicated they need to be.
Rather than keep the default controller/action and add routes for every view in home, you can add a route for each controller and then have your default route without a controller path.
While this means you do need a route for every controller, it's better than one for every view.
routes.MapRoute(
"AdminRoute",
"Admin/{action}/{id}",
new { controller = "Admin", action = "Index", id = UrlParameter.Optional });
routes.MapRoute(
"BrandRoute",
"Brand/{action}/{id}",
new { controller = "Brand", action = "Index", id = UrlParameter.Optional });
routes.MapRoute(
"HomeRoute",
"{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
routes.MapRoute(
"DefaultRoute",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
(afaicr you don't need the default route as all your views would be covered by the other 3 routes)
Note the path for 'HomeRoute' doesn't have a controller part.
As long as they are in this order any url with /Admin/ or /Brand/ will be picked up first.
First of all, I am very new to MVC and this is my first ever project.
I am trying to achieve the custom routing URL like the following:
http://mywebsite/MDT/Index/ADC00301SB
Similar to...
http://mywebsite/{Controller}/{Action}/{query}
In my RouteConfig.cs, I put the following
routes.MapRoute(
name: "SearchComputer",
url: "{controller}/{action}/{query}",
defaults: new { controller = "MDT", action = "Index", query = UrlParameter.Optional }
);
In My MDTController.cs, I have the following code
public ActionResult Index(string query)
{
Utils.Debug(query);
if (string.IsNullOrEmpty(query) == false)
{
//Load data and return view
//Remove Codes for clarification
}
return View();
}
But it's not working and I always get NULL value in query if I used http://mywebsite/MDT/Index/ADC00301SB
But if I used http://mywebsite/MDT?query=ADC00301SB, it's working fine and it hits the Controller Index method.
Could you please let me know how I could map the routing correctly?
You should add your MapRoute before default MapRoute, because order in RouteCollection is important
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "SearchComputer",
url: "{controller}/{action}/{query}",
defaults: new { controller = "MDT", action = "Index", query = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
One issue that I have encountered is that placing your route below the default route will cause the default to be hit, not your custom route.
So place it above the default route and it will work.
A detailed explanation from MSDN:
The order in which Route objects appear in the Routes collection is significant. Route matching is tried from the first route to the last route in the collection. When a match occurs, no more routes are evaluated. In general, add routes to the Routes property in order from the most specific route definitions to least specific ones.
Adding Routes to an MVC Application.
You can change it to
routes.MapRoute(
name: "SearchComputer",
url: "MDT/{action}/{query}",
defaults: new { controller = "MDT", action = "Index", query = UrlParameter.Optional }
);
I have a requirement in which I have to map the below url
/amer/us/en/ = Home controller
/amer/us/en/login/index = Home controller
/amer/us/en/confirmation = Confirmation controller
along with the regular default action.
Eg if user goes to
http:\\test.com --> http://test/home/index
http:\\test.com/amer/us/en/login/index --> http://test/home/index
http:\\test.com/amer/us/en/ --> http://test/home/index
I was looking into attribute routing and so I added the below code in HomeController
[RoutePrefix("amer/us/en/")]
[Route("{action=index}")]
public class HomeController : Controller
{
}
and I am getting this error
The route prefix 'amer/us/en/' on the controller named 'Home' cannot begin or end with a forward slash and also the default routing is not working now so http://test.com is not loading anything. Below is my default RouteConfig class.
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 = "Index", id = UrlParameter.Optional }
);
}
Very new to MVC. Can someone tell me what I am doing wrong here.
Routing in MVC works either by defining your routes in the RouteConfig class or by attribute routing (or you can use Areas). Routing with RouteConfig works with the order you define the routes with. When a request comes, MVC will try your routes from top to bottom and execute the first one that it can match with the requested url. So the routing need in your example can be achieved by:
routes.MapRoute(
name: "RootLogin",
url: "amer/us/en/login/index/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "DefaultAmer",
url: "amer/us/en/{controller}/{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 }
);
this will map login as a special route and all the other /amer/us/en/ routes will go to whatever controller comes after and whatever action of it. The last route, if the request does not start with /amer/us/en will perform the default behavior.
Looks like, however, you want to define /amer/us/en/ as an Area, so you might want to take a look into that as well.
I have a controller with an index action.
public ActionResult Index(int id = 0)
{
return view();
}
I wish to pass id into the index action, however it doesnt appear to work in the same way as the details action.
e.g. if I want to pass id 4 into the index action, I have to visit url:
http://localhost:8765/ControllerName/?id=4
With the details Action... I can do this.
http://localhost:8765/ControllerName/Details/4
What I want to do with Index is something like...
http://localhost:8765/ControllerName/4
When I visit this url, I get an error:
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /fix/1
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.17929
Is this possible? How can I get MVC to automatically treat the index action in the same way as the details one?
Thanks
UPDATE - MY CURRENT ROUTES CONFIG
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 }
);
}
}
UPDATE NEW RouteConfig Class still doesn't work when I visit localhost:1234/Fix/3
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 }
);
routes.MapRoute(
name: "FixIndexWithParam",
url: "Fix/{id}",
defaults: new { controller = "Fix", action = "Index", id = UrlParameter.Optional });
}
}
Update It's worth pointing out, /ControllerName/Index/4 should work with the default route.
With the default route there, it expects the second parameter to be the controller name.
So with the Default Route /ControllerName/4 is being interpereted as ControllerNameController Action 4, which of course does not exist.
If you add
routes.MapRoute(
name: "IndexWithParam",
url: "{controller}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
before the default one it would allow
/Home/4 to be routed to HomeController action Index with id=4
I have't tested this, it may conflict with the default. You may need to specify the controller explicitly in the route, ie:
routes.MapRoute(
name: "HomeIndexWithParam",
url: "Home/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
(Obviously, replace Home with whatever controller you're actually wanting to route to)