Mapping querystring value as controller in route - c#

I have website that shows user submitted content in 30+ languages in front page,I am currently using paths like:
http://www.example.com?lang=en
or if it's not first page
http://www.example.com?lang=en&page=2
But that really isn't user or seo friendly.
Is there a way in mvc to route these values to something like
http://www.example.com/en
and
http://www.example.com/en/2
without adding new action in-between like in this case lang:
http://www.example.com/lang/en/2
Update. Here is what I came up from Alexeis answer, in case anybody will need same thing:
In case of just language:
routes.MapRoute("MyLang", "{lang}", new { controller = "Home", action = "Index" },new { lang = #"\D{2}"});
In case you need language and optionally page:
routes.MapRoute("MyLang", "{lang}/{page}", new { controller = "Home", action = "Index", page = UrlParameter.Optional }, new { lang = #"\D{2}", page = #"\d+"});
It should not catch any other paths unless you have Actions with only 2 letters.

You don't need "lang/" for the route to match culture. Simple "{lang}" will do as long as you order routes in a way so other routes are matched correctly. You may also consider constraints on routing parameters to limit number of conflicts.
routes.MapRoute("MyLang", "{lang}",
new { controller = "Home", action = "Home", }
class HomeController{
public ActionResult Home(string lang)
{
return View();
}
}

u can add a new route like this
routes.MapRoute("MyLang", "{action}/{page}",
new { controller = "ControllerName",page=0 }
this way the lang name will automatically be mapped to the action and page will be passed as a parameter provided u have action signature as
public ActionResult English(int page)
obsly the return type and action name can be changed

Related

Is it possible to have a parameter named action in MVC4?

PLEASE MARK AS DUPLICATE - Its already answered here
Is it possible to have a parameter named action in MVC4?
Trying to do this results in the parameter returning me the name of the controller action rather than the parameter value.
/Somecontroller/Someaction?action=value
When I try to access the parameter action, I get "Someaction" as the result rather than "value".
Trying to bind the parameter to a different name doesn't help either.
public ActionResult Someaction([Bind(Prefix = "action")] String id)
Edit: I have not found 'Action'/'action' in reserved MVC keywords either.
I haven't tested this, but I would assume you could try changing the url of your default route to something other than action
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
to
routes.MapRoute("Default", "{controller}/{cAction}/{id}",
new { controller = "Home", cAction = "Index", id = UrlParameter.Optional });
this should then allow you to use action as a parameter in your Action. I'm not certain why you'd want to do this, I would probably build a route url that accepted my action and built it as part of the url similar to this:
/SomeController/SomeAction/value where value is your "action" parameter.
EDIT based on comments:
I successfully created a route that goes to an aspx url'd route
routes.MapRoute(null, "third-party.aspx", new { controller = "Home", action = "Index" });
Obviously you can add whatever controller/action you want here and where you want to handle it, then you access that route via /third-party.aspx?action=value and it seemed to work for me

How To Prevent Multiple ASP.NET MVC Route Mappings

I have an ASP.NET MVC routing question. First, let me explain my areas setup. It's quite simple.
Areas
|
+--Foo
|
+--Controllers
|
+--BarController.cs
I have a folder in my areas called "Foo" and controller called "BarController.cs" The Bar controller has several methods named "DoStuff1()", "DoStuff2()", etc.
My website uses the following URLs:
/foo/bar/15
/foo/bar/dostuff1
/foo/bar/dostuff2
The first URL requires an id and uses the default Index() method in the Bar controller to populate the webpage with a view and model.
In the second and third URLs, I'm using them for jQuery ajax calls.
Here is the code from my area registrion
context.MapRoute(null, "Foo/Bar/DoStuff1", new
{
action = "DoStuff1",
controller = "Bar"
});
context.MapRoute(null, "Foo/Bar/DoStuff2", new
{
action = "DoStuff2",
controller = "Bar"
});
context.MapRoute(null, "Foo/Bar/{id}", new
{
action = "Index",
controller = "Bar"
});
My problem is that for each new controller method I create, I have to add another route mapping in the area registrion file. For example, if I add the method DoStuff3(), I'll need to add this to the area registration:
context.MapRoute(null, "Foo/Bar/DoStuff3", new
{
action = "DoStuff3",
controller = "Bar"
});
How can I create a generic route mapping to handle the URLs I mentioned above that doesn't require new additions to the area registration file for new controller methods?
You can pull out the controller action.
Write the URL like this:
"Foo/Bar/{action}"
Additionally, you can pull out the controller as well, and write
"Foo/{controller}/{action}"
In this case, action = "Index" provides a default value of "Index" if no action parameter is provided.
In this case, you need to disambiguate between "Foo/Bar/{action}" and "Foo/Bar/{id}". Since matching is done in order, you'll want to put the id route first, and add a numeric constraint to the id parameter. This allows valid numeric ids to match it, and action names to skip down to the next route. Your two routes would look like this:
context.MapRoute(null, "Foo/Bar/{id}", new
{
action = "Index",
controller = "Bar"
},
new { id = #"\d+" });
context.MapRoute(null, "Foo/Bar/{action}", new
{
action = "Index", //optional default parameter, makes the route fall back to Index if no action is provided
controller = "Bar"
});
The default routing that comes with MVC templates are good for most of the needed route configurations.
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Url.Action doesnt work with non standard MVC Route

I am having trouble making #Url.Action work with Area's that have a non standard route structure.
For instance if I register this route in my Dashboard area:
context.MapRoute(
"Dashboard_default",
"Dashboard/{controller}/{action}/{id}",
new { controller = "View", action = "Display", id = UrlParameter.Optional }
);
and then in my layout view I call:
#Url.Action("Select", "View", new { area = "Dashboard" })
I get a proper url: /Dashboard/View/Select
However, if I change the route to include an optional secondary id like this:
context.MapRoute(
"Dashboard_default",
"Dashboard/{controller}/{action}/{id}/{secondaryid}",
new { controller = "View", action = "Display", id = UrlParameter.Optional, secondaryid = UrlParameter.Optional }
);
Then the same call to #Url.Action(...) doesn't return any url. If I specify those optional parameters with real values like so:
#Url.Action("Select", "View", new { area = "Dashboard", id = 1, secondaryid = 2 })
I do get a god return value of: /Dashboard/View/Select/1/2
The problem is that for some of my actions in this area don't need the id or secondary id and I want the url to be generated without them. If i set them to (int?)null it still doesn't work.
Am I doing something wrong? Shouldn't Url.Action(...) return the URL without the id and secondaryid tokens if I dont specify them in the routeValues parameter?
Having multiple optional parameters does funky things to your routes. Basically, the route engine cannot (has trouble) matching one or no optional parameters where there is a group of them. For more information, check out this blog post on the same issue.
Since you don't always need id or secondary id, just make a couple of routes to handle those cases.
context.MapRoute(
"Dashboard_IdAndSecondaryId",
"Dashboard/{controller}/{action}/{id}/{secondaryid}",
new { controller = "View", action = "Display"}
);
context.MapRoute(
"Dashboard_default_WithSecondaryId",
"Dashboard/{controller}/{action}/{secondaryid}",
new { controller = "View", action = "Display"}
);
context.MapRoute(
"Dashboard_default",
"Dashboard/{controller}/{action}/{id}/",
new { controller = "View", action = "Display", id = UrlParameter.Optional}
);
Now, when you send just an Id, just a secondaryId or both, you will have routes that will match. We can remove the optional parameter declarations in the first two routes, because in order to match that route, you would have to send the required parameters. Without sending the required parameters, you would want only the last route to match.
The last route is your default route when only Id or none is sent in the action link. I believe that this order works as well, keeping in mind you want your routes to go from most specific to least specific given that they are processed in order.

MVC special routing

I have an asp.net MVC project where i need to define some custom routes. Similar to what you see for posts on Wordpress where the route is of the form postid-postname:
12-i-am-post
I know how to do something like postid/postname:
12/i-am-post.
But how do I make a route that combines the two, such as:
mywebsite.com/12-postname-is-her
routes.MapRoute(
"PostRoute", // Route name
"{controller}/{id}-{postName}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional, postName = UrlParameter.Optional } // Parameter defaults
);
public ActionResult Index(int id, string postName)
{
return View();
}
Should work for the following request http://localhost/Post/1-MyPostName
Since there are multiple hyphens you won't be able to use it as a delimiter/separator, unless you want it to always match the first occurrence. Your best bet is to do a catchall {*path} and parse the value in your controller.

How this controller can get the values it needs?

Say I have set up a url structure as follows (ASP.NET MVC2)
http://localhost:XXXX/Product/
Click on link browse by color
http://localhost:XXXX/Product/Color/
Click on link browse red color items by type (i.e. pen's)
http://localhost:XXXX/Product/Color/Red/Pen
In the controller, I will need to do a select based on these criteria. Except when previously, I could go
public ActionResult ShowTypesForColor(string color)
but to do this one:
public ActionResult ShowItems(string type)
I also need the color that was selected.
How could I do this? Is splitting up the url string the only way?
edit: maybe i've gotten ahead of myself in the global.asax.cs
routes.MapRoute(null, "Product/Color/", new { controller = "Product", action = "ShowAllColors" });
routes.MapRoute(null, "Product/Color/{color}", new { controller = "Product", action = "ShowTypesForColor" });
routes.MapRoute(null, "Product/Color/{color}/{type}", new { controller = "Product", action = "ShowDetail" });
I don't think I can define the last one like that can I? with two {} values?
Your last route seems perfectly valid. It will map to action with signature like this:
ActionResult ShowDetails(string color, string type) {
return View(/*view params*/);
}
EDIT I think the order is wrong, so if the last route is not being fired, try doing this:
routes.MapRoute(null, "Product/Color/{color}/{type}", new { controller = "Product", action = "ShowDetail" });
routes.MapRoute(null, "Product/Color/{color}", new { controller = "Product", action = "ShowTypesForColor" });
routes.MapRoute(null, "Product/Color/", new { controller = "Product", action = "ShowAllColors" });
The order of MVC routes should be from most specific to least specific, otherwise the least specific route (/product/color/{color}) will match a url product/color/red/pen before the more specific /product/color/{color}/{type}
You can put multiple tokens in your route (e.g., {color} and {type}) but it's not going the work the way you have it there. Why have you defined "Color" as the second segment of your URL? Why not just do /Products/Red and /Products/Red/Pen? It's inconsistent to do .../Colors/Red and not .../Types/Pen so I'd just leave the "Colors" and "Types" qualifiers out altogether.
I'd define your ShowItems() method like this:
public ActionResult ShowItems(string color, string type)
this will allow you to have a route like /Products/Red/Pen where your route maps to this ShowItems() method. But you'll still need to differentiate that from the ShowTypesForColor() method where it also takes a first parameter of color. The routing framework will just treat type as null - for the route that has both tokens, make sure you have a route constraint specifying that neither color nor type can be null/empty (i.e., for the ShowItems() route).

Categories

Resources