There is any way to change the defualt views path in MVC3/4. i.e: The Url http://localhost:000/Home (the controller Home) will represent the view at Views/Style1/Home/Action.
Thanks ahead!
Ok, now that I understand the question better after the edit, I think this is what you're looking for:
You can change the ViewLocation in Application_Start().
The example below assumes use of the Razor View Engine.
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new RazorViewEngine { ViewLocationFormats = new string[] { "~/Views/Style1/{1}/{0}.cshtml" } } );
Answer was partially derived and referenced from this post
You should be able to set the Default route for your application to use a different base path. You can typically set the route in the Global.asax in the RegisterRoutes method.
Example:
routes.MapRoute(
"Default", // Route name
"Style1/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Related
I've recently added Areas to an existing MVC 4 web app. One of my areas has a Home controller, so obviously when I navigate to /MyArea/Home/Index I want to display it's Index view. Initially I was getting the following error:
Multiple types were found that match the controller named 'Home'. This can happen if the route that services this request ('{controller}/{action}/{id}') does not specify namespaces to search for a controller that matches the request. If this is the case, register this route by calling an overload of the 'MapRoute' method that takes a 'namespaces' parameter.
The request for 'Home' has found the following matching controllers:
MyApp.Controllers.HomeController
MyApp.Areas.MyArea.Controllers.HomeController
Researching the issue I found that I needed to add default namespaces to my calls to MapRoutes() and that's stopped the error. Unfortunately I now find that when I go to /MyArea/Home/Index the app actually displays the view for /Home/Index instead - I can't display actions from the Area's Home controller.
Here's my code:
Global.aspx.cs
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
MyApp.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},
namespaces: new[] {typeof(MyApp.Controllers.HomeController).Namespace}
);
}
MyApp.Areas.MyArea.MyAreaRegistration
public override void RegisterArea(AreaRegistrationContext context)
{
var ns = typeof(MyApp.Areas.MyArea.Controllers.HomeController).Namespace;
var routeName = AreaName + "_Route";
var routeUrl = AreaName + "/{controller}/{action}/{id}";
var routeDefaults = new {controller = "Home", action = "Index", id = UrlParameter.Optional};
var routeNamespaces = new[] {ns};
context.MapRoute(
name: routeName,
url: routeUrl,
defaults: routeDefaults,
namespaces: routeNamespaces
);
}
Anyone got any bright ideas on how to solve this?
Update:
The problem only occurs when calling an action that exists in both HomeController classes, like Index. Calling an action in the Area's HomeController that does NOT exist in the default HomeController displays the correct view.
Update 2:
Turns out that this was a classic PICNIC error - a simple typo in my code, so the action went looking for a view that did not exist. As such, it went for the first matching view it could find - the one in the "root"
You need to add new { Area = "MyArea" } in the routeValues parameter when you are linking to the one in the MyArea area.
In your RegisterArea function you should update the routeDefaults to also include the area name.
var routeDefaults = new {controller = "Home", action = "Index", area = AreaName, id = UrlParameter.Optional};
<facepalm>
In the process of importing the code for the Area I made a typo in the view's folder name, so MVC wasn't able to find the correct index.cshtml for the area action.
</facepalm>
By the looks of things, when MVC can't find the area action's view it uses the default view instead. Once I'd fixed the name of the folder in Areas\MyArea\Views to match the controller name everything worked as expected.
+1 to both of the folks who answered - your responses were helpful and I've employed both in my updated code
I have a request controller that is getting out of hand, and I want to divide the actions on several controllers while maintaining a clean URL. I'm trying to experiment with routing, but without success. I've read some examples and tutorials on routing, but, though I understand the examples, nothing seems to apply to my case, and I feel non the wiser. What I want is for the URL Requests/Approval to be handled on my ApprovalController instead of my RequestController, so I wrote the following.
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 = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Approval",
"Request/{controller}/{action}",
new { controller = "Approval", action="Index", id = "" }
);
}
But it's not working. Why? I have a folder in the my Views called Approval, and in there I have a file called Index.cshtml. How should I code the MapRoute?
Edit
I added all the routes I've got
You need to swap the two MapRoute statements, like so:
routes.MapRoute(
"Approval",
"Request/Approval/{action}",
new { controller = "Approval", action="Index", id = "" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
The reason it is currently not working is because the first statement ('Default' route name) is getting matched before the second one is even evaluated.
In addition (as noted in my above example,) you need to remove '{controller}' in the Approval route and replace with 'Approval'... unless you specifically want the URL /Request/{ANY controller}/{action} to go through, which I doubt. From your question it seems you only want /Request/Approval/ to go to your Approval controller.
Don't forget to keep the Default route at the bottom, so as to match your other controllers and actions. It serves as a catch-all should no other matches exist.
The order you map your routes matters. Move the second route before the default route.
You will still have a problem though, as any thing /request/something will look for the SomethingContoller. To fix this, change your route to this:
routes.MapRoute(
"Approval",
"Request/Approval/{action}",
new { controller = "Approval", action="Index", id = "" }
);
I have the following route:
routes.MapRoute(
"Default", // Route name
"{language}/{controller}/{action}/{id}",
new { language = "en", controller = "XY", id = UrlParameter.Optional }
);
For changing the language of the site, I would like to create links, which correspond exactly to the url of the current page, but have another language part.
What would be the best way, to generate such a link?
Most likely, you'll want to insert the {language} value as part of each link-rendering View's ViewModel or ViewData. There's a few different way you could achieve this; such as overloading your controller's OnActionExecuted() method. If you take this approach, I suggest making all of your controllers inherit from a single base controller.
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
filterContext.Controller.ViewData["Language"] = GetUserLanguage();
base.OnActionExecuted(filterContext);
}
And then in your View:
#Url.Action("Index", "Home", new { language = ViewData["Language"] })
Alternatively, you might consider overloading the Url.Action() and Html.ActionLink() methods with logic which appends this value automatically.
You could do something like this:
#Html.RouteLink("Switch Language", "Default", new {
controller = ViewContext.RouteData.Values["controller"],
action = ViewContext.RouteData.Values["action"],
id = ViewContext.RouteData.Values["id"],
language = "fr"
})
It would probably make sense to make an extension method to handle this though.
I thought I had at least a bases for understanding routing in MVC after all the documentation I have read, only to fail at it when attempting to utilize it.
I have the following two routes declared in my Global.aspx
routes.MapRoute(
"", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Admin", action = "List", 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
);
I have a AdminController that I have a few methods, one that is "List" method that renders a list of products to a "List" view.
I thought I understood how RedirectToAction works, and I added an "Add" method (see below) that adds a new Product and returns a RedirectToAction which I understood would be the proper way to redirect to the List action on the same "AdminController"
[HttpPost]
public ActionResult Add(Product product) {
if (_prodRepo.Add(product)) {
return RedirectToAction("List", "Admin");
}
return View("Add", product);
}
However, on the return of the "Add" it always attempts to route to the path website.com/Account/Login/ReturnUrl=%2f.
However, if I go to website.com/Admin it does render the list as I expect. But when using the RedirectToAction as in the example above, it attempts to go to the /Account/Login (Controller/action).
It was my understanding that the RedirectToAction("List", "Admin") would route to the "List" method on the AdminController controller and that I was using it as expected.
Can someone please help me understand the reasoning behind this. But also, could someone post some recommended articles for understanding the whole MVC routing including how the web.config works with routing.
Finally, it was also my understanding that route discovery by the framework is done in the order they are specified in your routes.MapRoute() declaration and stops at the first one that matches. Therefore, if the first one is listed as Controller = "Admin", Action = "List", I would expect by convention that this is the correct route it would first match and return.
Your routes need to be different (the url parameter) since the first route with a matching url will be used.
This will therefore work for you:
routes.MapRoute("Admin",
"admin/{action}/{id}",
new { controller = "Admin", action = "List", id = UrlParameter.Optional });
The defaults (third parameter in the method) are used if the parameters isn't found/specified in the uri.
As for your question regarding /Account/Login/ReturnUrl=%2f. The login redirections are handled by the MembershipProvider and not by the standard routing mechanism.
I am learning MVC and I need to understand why it doesn't work the way it should.
Here is my routing :
public static void RegisterRoutes(RouteCollection routes)
{
// Note: Change the URL to "{controller}.mvc/{action}/{id}" to enable
// automatic support on IIS6 and IIS7 classic mode
//http://localhost/store/category/subcategory/product
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Category", // Route name
"store/{category}/{subcategory}", // URL with parameters
new
{
controller = "Catalog",
action = "Index",
category = "Featured Items",
subcategory = "All Items"
}
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" }, // Parameter defaults
new { controller = #"[^\.]*" } // Parameter constraints
);
}
The way I understand routing I should see the following url when I start the web app :
http:/localhost/store/
What I get is the second route....
Furthermore if I change the second route to "home/{action}/{id} it doesn't catch any routes.
Could you help me understand this please..Thanks
Routes do not specify default URL; the default URL is handled by your app. Routing specifies that when it sees http://localhost/store/bikes/mountain, it will use the catalog controller. But that doesn't specify the default URL; you have to enter that in the project properties.
I would recommend not changing the second one because unless you are creating groupings for all of your controllers, it's best to have the default as it is so you can catch all URL's. Your change to the second one would require the url to be:
http://localhost/home/home/index to match the HomeController's index action, whereas the default setup catches http://localhost/home/index...
Does that make sense?
Try this: http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx