Can I have more than one action in a single routemap? - asp.net-mvc

I have the following route set up:
context.MapRoute(
"MyAccount_default",
"MyAccount/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
and the following links:
/MyAccount/Access/Login
/MyAccount/Access/Logout
/MyAccount/Access/Register
Is there some way that I can create a routemap so that entering:
/Login
/Logout
/Register
Would direct the request to the MyAccount area, Access controller and Login/Logout or Register methods? If I have
the routemap then can it belong inside the routemap of the MyAccount area or does it need to be outside that?

You really should be specific with your routes. If you want something outside of the standard routes, add those to your route tables.
context.MapRoute(
"Login",
"/Login",
new { controller="Access", action = "Login"}
);
Add that before your default route.
The other option is to use our default route, but in addition use something like the AttributeRouting project at https://github.com/mccalltd/AttributeRouting
and specify your additional route on your action methods in each controller.
note that you could code on your Login action method something like:
[GET("Login")]
public ActionResult Login()
{
}
so your default routes would be used and in addition this extended route. I believe that should work anyways :)

Related

ASP.NET MVC4 Routing - Multiple routes to the same location

I am in the process of setting up a Single Page Application (SPA) and would like to setup, currently two routes. For instance:
Route 1: http://localhost - this is the default route which requires authentication (Admin area)
Route 2: http://localhost/<client>/<clients project name>/ - this does not require authentication (view only)
In the admin area, they setup the <client> and <clients project name>, therefore I know I need to setup this configuration in MVC4 Routes, but it is unclear to me how I would approach this.
Another caveat would be, if the <clients project name> was not entered into the URL, it would present a search page for that client.
One of the great things about routing in MVC is the ability to route anything to anywhere, regardless of whether the url matches the naming of controllers and action methods. The RouteConfig allows us to register specific routes to cater for this. Let me show you how you can achieve this.
Route 1:
This is handled by the default route in the route config.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home",
action = "Index",
id = UrlParameter.Optional });
Hitting http://localhost will take you to the Home controller and the Index action method.
Route 2:
We can set up one route that will cater for http://localhost/<client> and http://localhost/<client>/<clients project name>
routes.MapRoute(
"Client",
"{client}/{title}",
new { controller = "Home",
action = "Client",
title = UrlParameter.Optional });
Hitting either http://localhost/bacon or http://localhost/bacon/smokey will take you to the Home controller and the Client action method. Notice the title is an optional parameter this is how we can get both urls to work with the same route.
For this to work on the controller end our action method Client would need to look like this.
public ActionResult Client(string client, string title = null)
{
if(title != null)
{
// Do something here.
}
}

MVC Routing access path

I am quite new to MVC. I am facing a problem with routing right now. My project URL is /account/Create. I can access controller and do my stuff for Create, but
I need to access /account controller because I need to write code in that level.
/account/create - I can access the code this level
/account - dont know how to access this controller
Project Stucture:
Sample Project
Controler
Model
View
What am I supposed to change in the following code?
//global.asax.cs
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
);
}
/account/create is accessing code in the Account controller. Create has to be a method on the Account controller (unless you modify the default routes). Any public method you define on the account controller is accessible via /account/method URL. Based on the route you posted, going to /account URL is going to call the account controller Index method:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
**new { controller = "Home", action = "Index", id = UrlParameter.Optional }** // Parameter defaults
);
That action = "Index" part above is defining what the default method on the account controller is, so going to /account URL is equivalent in this case to /account/index URL
And I just noticed that you spelled account wrong in the question, not sure if that may be your issue ;)
Update
Not sure if this is what you're after, but if you need to write code at the /Account level you can do this in the constructor of the controller.
Unless you substantially customize MVC, then controllers correspond to classes derived from Controller in mvc, and actions correspond to methods on those controllers.
What are you trying to achieve when you say you can't access the controller /Account?
The controller is only a container for Actions so you need to specify an Action. Of course, you can have a default Action in case an action isn't specified. That is specified in default the route above. It's called Index

Does ActionLink take into account Global.asax routes?

I have an action like so:
#Html.ActionLink(dinner.Title, "Details", new { id=dinner.DinnerID })
and a route defined like so:
routes.MapRoute(
"PrettyDetails",
"{Id}",
new { controller = "Dinners", action = "Details" },
new { Id = #"\d+" }
);
The action link renders My Dinner
Why does it not display "Details" in the link? Is it because it knows about the routes defined in Global.asax and therefore matches the pattern somehow?
Thanks
Why does it not display "Details" in the link?
Because the route pattern you have defined in your Global.asax is {Id} where id must be an integer. So to answer your question, yes, the Html.ActionLink helper respects the routes you have defined in your Global.asax.
If you want to be able to pass a different action than details you will have to modify your pattern. For example like this: {action}/{id}. Obviously the same stands true for the controller part.
You could use the Html.RouteLink which allows you to specify a route name if you don't want the evaluation to happen in the order of your route definitions in Global.asax. This way you could target a specific route. Of course the arguments you are passing must be coherent with this route.
The answer is "Yes", ActionLink is taking the defined routes into account when rendering the URL.

asp.net mvc routing: how to use default action but non-default parameter?

I'm rewriting the question, as the answers so far show me that I have not defined it good enough. I'll leave the original question for reference below.
When you set up your routing you can specify defaults for different url/route parts. Let's consider example that VS wizard generates:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "DefaultPage", action = "Index", id = UrlParameter.Optional } // Parameter defaults
In this example if controller is not specified, DefaultPageController will be used and if action is not specified "Index" action will be used.
The urls will generally look like: http://mysite/MyController/MyAction.
If there is no action in Url like this: http://mysite/MyController then the index action will be used.
Now let's assume I have two actions in my controller Index and AnotherAction. The urls that correspond to them are http://mysite/MyController and http://mysite/MyController/AnotherAction respectively. My "Index" action accepts a parameter, id. So If I need to pass a parameter to my Index action, I can do this: http://mysite/MyController/Index/123. Note, that unlike in URL http://mysite/MyController, I have to specify the Index action explicitly. What I want to do is to be able to pass http://mysite/MyController/123 instead of http://mysite/MyController/Index/123. I do not need "Index" in this URL I want the mvc engine to recognize, that when I ask for http://mysite/MyController/123, that 123 is not an action (because I have not defined an action with this name), but a parameter to my default action "Index". How do I set up routing to achieve this?
Below is the original wording of the question.
I have a controller with two methods definded like this
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(SomeFormData data)
{
return View();
}
This allows me to process Url like http://website/Page both when the user navigates to this url (GET) and when they subsequently post back the form (POST).
Now, when I process the post back, in some cases I want to redirect the browser to this url:
http://website/Page/123
Where 123 is some integer, and I need a method to process this url in my controller.
How do I set up the routing, so this works? Currently I have "default" routing generated by the wizard like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "DefaultPage", action = "Index", id = UrlParameter.Optional } // Parameter defaults
I tried adding another controller method like this:
public ActionResult Index(int id)
{
return View();
}
But this doesn't work as ambiguous action exception is thrown:
The current request for action 'Index'
on controller type 'PageController'
is ambiguous between the following
action methods:
System.Web.Mvc.ActionResult Index() on
type PageController
System.Web.Mvc.ActionResult
Index(Int32) on type PageController
I must add, that I also have other actions in this controller. This would have worked if I didn't.
Here is how this can be resolved:
You can create a route constraint, to indicate to the routing engine, that if you have something in url that looks like a number (123) then this is an action parameter for the default action and if you have something that does not look like a number (AnotherAction) then it's an action.
Consider This code:
routes.MapRoute(
"MyController", "MyController/{productId}",
new {controller="My", action="Index"},
new {productId = #"\d+" });
This route definition will only match numeric values after MyController in http://mysite/MyController/123 so it will not interfere with calling another action on the same controller.
Source: Creating a Route Constraint
If you keep the variable name to remain being ID, you don't need to change anything.
Rename the post one to "PostIndex" and add this attribute:
[ActionName("Index")]
Same question on SO here.
Ok, here's a cut/paste answer for you, if that helps.
public ActionResult Index() {
return View();
}
[AcceptVerbs(HttpVerbs.Post), ActionName("Index")]
public ActionResult PostIndex(SomeFormData data) {
return View();
}
Oh i got it now. I think It's not possible with default route, You need to map custom routes.
// /MyController/AnotherAction
routes.MapRoute(
null,
"MyController/AnotherAction",
new { controller = "DefaultPage", action = "AnotherAction" }
);
// /MyController
// /MyController/id
routes.MapRoute(
null,
"MyController/{id}",
new { controller = "DefaultPage", action = "Index", id = UrlParameter.Optional }
);
ps. Default routes like /MyController/id must mapped at last.
I think you want return the same view, but you need understand you are doing two differents things. One is receive post, and another is accessing by get, and another is accessing by get and parameter...
You should do 3 actionresult with different names, and return de same view as View("ThisIsTheResult")

How can i create a route that returns a URL without controller reference in ASP.NET MVC

I have a controller call DefaultController. Inside this controller i have views for what would be the equivalent of static pages.
The URLs look like www.site.com/Default/PageName
Is it possible to create a route that would format these URL like:
www.site.com/PageName
I want to avoid creating controllers for each of these. An alternative would be to create .aspx pages in the root but can i create routes for these pages ie:
www.site.com/PageName.aspx becomes www.site.com/PageName ?
Thanks!
You can create explicit route for the PageName action on the DefaultController like this:
routes.MapRoute(
"PageName",
"pagename",
new { controller = "DefaultController", action = "PageName" }
);
You have to put this route before the default MVC route. The biggest drawback for this approach is that you have to create one route per static page.
An alternative approach would be to add an additional route after the default MVC route:
routes.MapRoute(
"DefaultController",
"{page}/{*path}",
new { controller = "DefaultController", action = "{page}" }
);
The drawback for this approach is that this rule would be handling all the URLs, even those that would normally return 404.
First approach
Create a route that catches actions:
routes.MapRoute(
"Catcher1",
"{action}",
new { controller = "Default", action = string.Empty });
But this means you'd have to create just as many controller actions on your default controller.
Second approach
If you'd like to avoid that as well and have just one controller+action instead, write a route this way:
routes.MapRoute(
"Catcher2",
"{path}",
new { controller = "Default", action = "PageName", path = string.Emtpy },
new { path = #"[a-zA-Z0-9]+" });
This route also defines a route constraint so it will catch only those routes, that actually have something in first route segment. You can define this constraint to only catch those requests that you need (ie. path = "Result|Search|Whatever")
then your DefaultController would have something like this:
public ActionResult PageName(string path)
{
// code goes here
}
Second approach seems very feasible, but I wouldn't recommend it because all logic would have to go through this controller action (for these kind of requests). It would be better to separate these actions into logical ones. Those that actually do the same thing (so they wouldn't have a bunch of switch statements or similar) would be defined with separate routes (if they couldn't be done using a single one).

Resources