Can't get MVC Routing to work - asp.net-mvc

I have a site and the url looks like this;
Home/LocationPage?locationId=f25a9ba4-54dc-4e6a-bdbf-094a5a6f7801
What I would like it to look like is;
Home/My Restaurant
I've tried mapping routes like this;
routes.MapRoute(
"Location",
"{Controller}/{LocationName}",
new { controller = "Home", action = "LocationPage", LocationName = "" }
But can't seem to get the URL to change at all.

Keep the route you just made, but you may need to add in a couple more things.
Add in a route constraint (or override the OnActionExecuting method on the controller or add a attribute to the action method) that looks up the the LocationName route parameter in the database and (if found) adds a locationId parameter to the route parameters. Then create an action called LocationPage that takes a locationId (location Name is optional).
That way you get nice urls coming in, but the action doesn't need to do the lookups.

If you receive a parameter called LocationId in your Action then you need to change your route:
routes.MapRoute(
"Location",
"{Controller}/{LocationId}",
new { controller = "Home", action = "LocationPage", LocationId = "" }
And don't forget that in this way you wouldn't get this parameter as Guid then you should make your logic to retrieve the Guid value by the provided name.

Related

MVC4 Razor Appending ID to a url using route.config

I just cant achieve my goal of getting an id to appear in a URL. Here is an example of what I have done so far.
Here is my BlogController:
public ActionResult BlogPost(int hiddenBlogId)
{
TempData["id"] = hiddenBlogId;
return View(_repository);
}
Here is my route.config:
routes.MapRoute(
"MyBlog", // Route name
"blog/{action}/{id}", // URL with parameters
new { controller = "Blog", action = "blogpost", id = #"0|-?[1-9]\d*" } // Parameter defaults
);
I am completely missing the point somewhere. How can I pick up the parameter which went into my method/action BlogPost and then display it in the output URL.
http://www.mydomain/controller/id
It's so that in the end I should be able to display the title for each blog. I'm using an ID just for simplicity for now. Any help at all would be greatly appreciated.
Your route definition says that the third value is called id, but you are trying to bind hiddenBlogId in the method. The two names need to match. Change the hiddenBlogId action method parameter to id, or map a new route with the {hiddenBlogId} placeholder.

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")

MVC Route parameters

If I have this route:
routes.MapRoute(
"BlogRoute", // Route name
"blog/{action}", // URL with parameters
new { controller = "Blog", action = "Index", id="abc" } // Parameter defaults
);
... and have this Index method in the controller:
public ActionResult Index(string id)
{
return View((object)id);
}
Is it possible for someone to change that id parameter from "abc" to something else? For example, by appending ?id=somethingElse to the URL? I tried that but it didn't change it. So is it guaranteed that I'll always get "abc" in the Index method?
Basically I need to send a hardcoded string when one route is chosen and I don't want the user to be able to change this string via the URL or any other mechanism. It's like "abc" is a password (it's not but just assume it is). Only the developer is allowed to set this string by editing Global.asax.cs.
Is it possible?
You can add a constraint for the id parameter using the regular expression /abc/

ASP.NET-MVC . How to get the controller name from an url?

How can I get the controller name of a relative Url, using the routes I have defined in Global.asax?
Example:
if I have a route defiend like this:
routes.MapRoute(
"Default", // Route name
"{language}/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "", language = "en" }
from the string "~/en/products/list" I want to have products (the controller name). Is there any existing method that already does this?
You should probably add another route like George suggests but if you really just need the controller value derived from the route you can do this in your controller action methods:
var controller = (string)RouteData.Values["controller"];
See Stephen Walther's blog post ASP.NET MVC Tip #13 – Unit Test Your Custom Routes
The project MvcFakes has an old System.Web.Abstractions reference. So you must replace it
with the new one and recomply the project to get MvcFakes.dll.
This is my code:
public string getControllerNameFromUrl()
{
RouteCollection rc = new RouteCollection();
MvcApplication.RegisterRoutes(rc);
System.Web.Routing.RouteData rd = new RouteData();
var context = new FakeHttpContext("\\" + HttpContext.Request.Url.AbsolutePath);
rd = rc.GetRouteData(context);
return rd.Values["action"].ToString();
}
In my code above "MvcApplication" is the class name in the Global.asax.
Good luck !
I'm not sure what you're asking, so if my answer's wrong, it's because I'm guessing at what you want.
You can always add another route to your Global.asax. That's often the easiest way to deal with cases 'outside of the norm'.
If you want to return a list of products, you'll use this route:
routes.MapRoute(
"ProductList",
"{language}/{products}/{action}/",
new { controller = "Products", action = "List", language = "en" });
You can also replace products with the more generic {controller} if more than one type of entity is going to use this route. You should modify it for your needs.
For example, to make this a generic route that you can use to get a list of any product:
routes.MapRoute(
"ProductList",
"{language}/{controller}/{action}/",
new { controller = "Products", action = "List", language = "en" });
What this does is that it creates a route (that you should always place before your Default route) that says, "For whatever the user enters, give me the controller and action they ask for". (Such as /en/Products/List, or /en/Users/List).
To visit that controller, you simply need to navigate to the following: yoursite.com/en/products/list. You can also use the HTMLActionLink to visit the controller.
<%=Html.ActionLink("Product", "List", new { controller = Products }, null ) %>
I'm writing this without my IDE open, so the ActionLink may have an error in it.

Why is this MVC route not working?

here are two routes from my global.asax file. I'm trying to go to the second route and I'm getting a default 404 resource not found error.
When i remove the first route (listed in this example), it works.
How can i fix this, please?
Snippet of global.asax code
// GET: /user/PureKrome/Alert/69
routes.MapRoute(
"User-Alert-Details",
"user/{displayName}/alert/{alertId}",
new { controller = "Account", action = "AlertDetails", alertId = 0 });
// GET: /user/PureKrome/Alert/create
routes.MapRoute(
"User-Alert-Create",
"user/{displayName}/alert/create",
new { controller = "Account", action = "AlertCreate" });
Your first route is a "greedy" route and will happily accept "create" as the alertId in the last parameter. It appears that you intend the alertId parameter to be numeric only, so you should add a constraint to tell the route system that that last parameter must be numeric.
See this tutorial.
For example:
// GET: /user/PureKrome/Alert/69
routes.MapRoute(
"User-Alert-Details",
"user/{displayName}/alert/{alertId}",
new { controller = "Account", action = "AlertDetails", alertId = 0 },
new { alertId = #"\d+" });
// GET: /user/PureKrome/Alert/create
routes.MapRoute(
"User-Alert-Create",
"user/{displayName}/alert/create",
new { controller = "Account", action = "AlertCreate" });
Note, you can also reverse the order of the routes, but even if you do, you should still include a constraint for correctness if you want alertId to always be a number.
You want the routes to be defined the other way round so that the exact match on create comes before the unconstrained match for alertId. That, or you can add a constraint to alertId as stated by Twisty Maze.
This is because the routing works by trying to match the routes from top to bottom. /user/PureKrome/Alert/create matches on the User-Alert-Details route as it thinks create is the value for alertId. By switching them around it will only match the User-Alert-Create route if the 4th segment is explicitly create and it will fall through to User-Alert-Details if it doesn't.
For clarity, they should work this way around:
// GET: /user/PureKrome/Alert/create
routes.MapRoute(
"User-Alert-Create",
"user/{displayName}/alert/create",
new { controller = "Account", action = "AlertCreate" });
// GET: /user/PureKrome/Alert/69
routes.MapRoute(
"User-Alert-Details",
"user/{displayName}/alert/{alertId}",
new { controller = "Account", action = "AlertDetails", alertId = 0 });
If you have another issue like this, try Phil Haack's url debugger at http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx
The problem is that you have specified Default Values for controller and actions in your first Mapping.
Now any incoming request is handled by the first route, if the controller name is missing, its replaced by the default value and if the action name is missing that is also replaced by the default value.
So in reality when you say http://localhost/SomeRoute
The first mapper comes into action and considers the string "SomeRoute" as a Controller name, then it does not find the action so it uses the default action you specified which is "AlertCreate" in your example.
So now the mapper tries to find a Action called AlertCreate in the "SomeRoute" controller.
Bottom line is the second mapping does not kick into action because the first mapping is handling all your routing request. (because you have default values specified)

Resources