routing with just one of two parameters of controller - asp.net-mvc

I have an actionresult with two parameter:
public ActionResult Index(int a,string b)
{
//some code
return View(b);
}
it creates this url automatically:
mysite.com/a=1&b=http://site.com/b=1
I just need to show first parameter "a" in my url:
mysite.com/a=1
I use the default route of MVC that creates in global.ascx:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
what should i do?
Thanks...

If you are seeing the "b" parameter bleed through from the current request, you can set the "b" parameter explicitly to empty string to avoid this behavior:
#Html.ActionLink("Home", "Index", "Home", new { a = 1, b = "" }, null)
I reported this "feature" as a bug, but the developers at Microsoft seem to think this behavior is supposed to make your URLs easier to configure, and they don't intend to fix it.
What you're seeing here is a feature of routing where "ambient" values (i.e. values that were detected in the incoming request's URL) are used to simplify (sometimes...) the generation of routes to other pages.
You can check our my answer (under the name "Eilon") in this StackOverflow post, where I explain the behavior in a bit more detail:
How Can I Stop ASP.Net MVC Html.ActionLink From Using Existing Route Values?
Ultimately if you want the most control over what gets generated for a URL there are a few options to consider:
Use named routes to ensure that only the route you want will get used to generate the URL (this is often a good practice, though it won't help in this particular scenario)
Specify all route parameters explicitly - even the values that you want to be empty. That is one way to solve this particular problem.
Instead of using Routing to generate the URLs, you can use Razor's ~/ syntax or call Url.Content("~/someurl") to ensure that no extra (or unexpected) processing will happen to the URL you're trying to generate.
Thanks,
Eilon

Related

MVC .NET 4 MapRoute + ActionLink or RouteLink issue

Okay, so here's the deal. I've got controller called "Hotel" with view called "Index", where I'm trying to produce code allowing me to generate links in form of:
../Hotel?id=1
with ID passed as argument. To do so, I've tried using MapRoute:
#Html.RouteCollection.MapRoute("Hotel", "../{controller}/{id}", new { controller = "hotel" });
together with ActionLink:
#Html.ActionLink("More >>>", "", "Hotel", new { id = item.HotelId }, null)
But the outcome link goes like this:
Hotel/Index/1
Which leads to correct location, but burns visual consistency of all links at my website. I've tried RouteLink as well, but with no success.
Thanks in advance!
Do you want to make all links in the application use the standard querystring format for parameters named "id"? If so, removing the {id} from url and defaults object in the "Default" route should do that for you just fine.
If you want to limit it to the "Hotel" controller, you are on the right track w/ the custom route. First, make sure the custom route comes before the default route definition, and second, define it with nothing beyond the controller/action like:
routes.MapRoute(
"HotelRoute", // Route name
"Hotel/{action}/", // URL with parameters
new { controller="Hotel", action = "Index" } // Parameter defaults
);
Any params you pass in should then be appended to the query string as a name/value pair.

Setting up ASP.Net MVC 4 Routing with custom segment variables

I just began working on an application with a couple areas (basic grid master / details type system..) I'm looking into taking advantage of the nice routing features in MVC (4 specifically) and I'm "just not getting it" I presume.
Currently the only route defined is the basic one:
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Account", action = "Index", id = UrlParameter.Optional }
);
which is fine, it works with the areas we have defined, so I'm assuming it must know where the user is and route to the appropriate controller based contextually on the location / area that the user is in.. so far nice..
Now, i'm trying to set up a new route that can handle
/someController/someAction/{statusName}
and specifically something like:
/OrderManager/List/New
AND
/OrderManager/List/Viewed
where "New" is the "New" status and have the Action Signature look like:
public ActionResult List(string statusName)
i was assuming I could just add the new route below the default one identifying "statusName" instead of Id, but of course, how the H would the routing mechanism know the difference between :
/controller1/action1/15
/controller2/action2/new
I did try adding a "static" route in the form of
routes.MapRoute("Default",
"ControllerName/ControllerAction/{statusName}",
new { statusName = UrlParameter.Optional }
);
I thought I could "hiJack" just that one route and do something special with it, but to know avail, the router stops at first match?? I'm assuming that was the wrong way to address this issue anyhow..
so now I'm going through the idea of getting to something like:
/somecustomroutename/somesortValue
ex.
/OrderManagerList/viewNew
where these routes would basically be "aliases". I had thought that adding the following route would do the trick:
routes.MapRoute("Default_List",
"OrderManagerList/{statusName}",
new {controller="OrderManager", action="List", statusName= UrlParameter.Optional }
);
with the associated action on the OrderManager controller:
public ActionResult List(string statusName)
no matter what I try, the argument is null, or the "resource cannot be found"
I know the controllers need to have a corresponding View file.. but that's not the issue here, the issue is my attempt at understanding the routing..
SO my questions.. fundamentally, what am I missing about the routing in MVC (4)? even some good articles for a simpleton like myself to understand?
my understanding; define a route, and map it's "endpoint".. however, i think i'm not understanding the assumptions that the machine is making..
anyhow, let me know if further explain / edit is required..
thanks in advance.
The basic principle of routes is that they are evaluated from the top down, and the routing systems uses the first match, not the best match.
The implication of this is that you must order your routes in order of specificity, with the most specific route first and the most general route last.
With this principle in mind, let’s look at your situation. Initially, you have only the default route defined:
routes.MapRoute("Default",
"{controller}/{action}/{id}",
new { controller = "Account", action = "Index", id = UrlParameter.Optional }
);
The URL pattern is "{controller}/{action}/{id}". By itself, this would match any three-segment URL, and would not match any URL that had less than three segments. However, the third input parameter is the default parameter, which defines defaults for the first and second segment and indicates that the third segment is optional. The next effect of this is to make the route match URL having 0,1, 2 or 3 segments.
Now you want to add a route where the third URL segment is mapped to a “statusName” parameter, and can handle URLs like:
OrderManager/List/New
OrderManager/List/Viewed
There are two basic approaches you can take here. You can 1) create a very specific route that will handle these two URLs only, or 2) you can try and create a more general route to handle the general case. Let’s look at the first case first. You can create a route as follows:
routes.MapRoute("", "OrderManager/List/{statusName}",
new { Controller = "OrderManager", Action = "List" });
Note that because this route is more specific than the default route, you must put this route before the default route.
If you want to have a more general route, you need to decide how this route will differ from the default route, since they both will match URLs having three segments. Let’s say you decide that the new route will accept anything that only contains letters in the third segment, leaving the default route to handle anything containing numbers. You can do this using route constraints. For example you could write a route as follows:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
constraints: new { id = #"^\d+$" });
routes.MapRoute(
name: "NewRoute",
url: "{controller}/{action}/{statusName}",
defaults: new { Controller = "OrderManager", Action = "List" },
constraints: new { statusName = "^[A-Za-z]+$" });
With these two routes, any three-segment URL having only letters in the third segment will put the third segment into a variable called “statusName”, whereas any URL with an integer in the third segment will put the third segment into a variable called “id”.
In any applications of real complexity, routes can get complicated, and it is very advantageous to write unit tests for your routes, to insure that you don’t screw things up when you add or modify a route.
For good references on routing, see Scott Sanderson's book or see the MSDN documentation

How can I achieve clean URL routing with custom user ID?

My ASP.NET MVC site allows users to register and give themselves user names, which will be unique and allow others to browse their pages with a clean URL that includes their name, like Twitter, Facebook, LinkedIn etc. do.
For example:
mysite.com/michael.guthrie
mysite.com/john
mysite.com/john/images
mysite.com/john/blog
etc.
The problem is that the first URL segment might be used for other "regular" controllers/actions, like:
mysite.com/about
mysite.com/register
So basically I seek for a routing scheme that says something like: If the first URL segment is a known controller, treat it as a controller (and parse the relevant action and parameters as usual), but if not - treat it as a user name, and pass it to a dedicated controller+action which will parse it and continue accordingly.
I don't want a solution that will enforce me to add routes for every specific controller that I have, such that after the routing module will go over all of them and won't find a match, it will get to the last one which defines a route for this special user name segment. The reason is primarily maintenance (I must remember to add a route every time I code a new controller, for example.)
I assume I can implement my own MvcRouteHandler / IRouteHandler but I feel there must be simpler solution that won't have me tweak MVC's out-of-the-box routing mechanism.
Note: I've read How to achieve nice litle USER page url like facebook or twitter? and it doesn't answer my question, it's just says that there is a URL rewriting module.
Do you know any good, elegant, clean way to achieve that?
You should have your first route be your Usesr route, with a route constraint along the lines of what I described in this answer: MVC routing question.
If your route is in the form {username}/{controller}/{id}, this route should cover all contingencies.
in the global.asax file you can map your routes
in the registerRoutes() method you can do something like this:
routes.MapRoute(
"ToonStudenten", // Route name
"{controller}/{action}/{userID}, // URL with parameters
new { controller = "Docent", action = "ToonStudenten", userID = UrlParameter.Optional} // Parameter defaults
);
I believe you can change the way your views look with this mapRouting, not entirely sure how though.. will try and search it up
You may want to take a look at this post:
MVC 3 keeping short url
You don't need to set a route for each URL. With a little help from route constraints you can do something like this:
routes.MapRoute(
"Home", // Route name
"{action}", // URL with parameters
new { controller = "Home", action = "Index" }, // Parameter defaults
new { action = "TaskA|TaskB|TaskC|etc" } //Route constraints
);
routes.MapRoute(
"Account", // Route name
"{action}", // URL with parameters
new { controller = "Account", action = "Logon" }, // Parameter defaults
new { action = "Logon|Logoff|Profile|FAQs|etc" } //Route constraints
);

Routing-MVC-ASP.NET

In most of the articles, they put this code and explain it but I feel I am not getting it. could any body expalain it in simple terms please.
This question is looks simple but I cannot get it correct in my head.
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
);
My Questions:
Why do we use route.IgnoreRoute and why the parameters in {} ?
Maproute has First parameter-Default, What that resembles, Second Parameter-"{controller}/{action}/{id}", What this for and third parameter, we use new ?
How do I intrepret these routing?
Why all these?
I have used webforms so far and Cannot get it in?
Any Gurus in MVC could explain all these please?
Why do we use route.IgnoreRoute
This tells routing to ignore any requests that match the provided pattern. In this case to ignore any requests to axd resources.
and why the parameters in {} ?
The {} indicates that the delimited string is a variable. In the ignore route this is used so that any .axd requests are matched.
Maproute has First parameter-Default, What that resembles,
The first parameter is the route name. This can be used when referring to routes by name. It can be null which is what I tend to use.
Second Parameter-"{controller}/{action}/{id}", What this for
This is the pattern that is matched. In this case it is setting up the default route which is a url formed by the controller name, action name and an optional id. The url http://mysite.com/Foo/Bar would call the Bar method on the Foo controller. Changing the url to http://mysite.com/Foo/Bar/1 would pass a parameter with the identifier id and value 1.
and third parameter,
The third parameter supplies defaults. In the case of the default route the default controller name is Home and the default action is Index. The outcome of this is that a request to http://mysite.com would call the Index method on the Home controller. The id part of the route is specified as being optional.
we use new ?
The new keyword is creating an object using the object initializer syntax that was introduced in version 3 of the .Net framework. Microsoft article.
The major advantage of using routing is that it creates a convention for your urls. If you created a new controller called Account and action methods called Index and Review then the methods would be availble at /Account and Account/Review respectively.
First of all: ASP.NET MVC is not a simple version of webforms.
MVC has a special structure. You can find a MVC description here: http://en.wikipedia.org/wiki/Model-View-Controller
MapRoute adds the URL structure mapping. For example, following the default route link like www.domain.com/home/users/1 means that the server should call the users action in the controller called home. The action gets a parameter called id with the value of 1.
If you want to add the new Route you can simply add this uin next way:
routes.MapRoute(
"NewRoad", // Route name
"/photos/{username}/{action}/{id}", // URL with parameters
new { controller = "Photos", action = "Index", string username, id = UrlParameter.Optional } // Parameter defaults
);
following this road the url will be: domain.com/photos/someuser/view/123. We can map the optional parameters like id, and static parameters, like username. By default we call photos controller and index action (if the action not set in ult, server will call default action "index", we set it in the route).

ASP.NET MVC routing issues

I'm having some issues trying to setup my Routing in MVC. I think I understand how it works, but I just can't seem to set the proper paths.
Basically I want to do something similar to how StackOverflow works so:
http://localhost/faq
I want this to grab the HomeController, hit the faq action and return the faq view. I can't seem to figure out how to do this.
Also, I tried adding a new route for something like this:
http://localhost/Boxes/25
So, Boxes is the controller, 25 is obviously the id(parameter). Similar to how stackoverflow has: https://stackoverflow.com/questions/[question number]/[question title]
So I tried doing this:
routes.MapRoute(
"Boxes",
"Boxes/{boxnumber}",
new {
action="Details", cubenumber = ""
}
);
with no success.
I've also downloading the Route Tester app, but that doesn't seem to be helping at this point. Most likely I need to really read up on how routing works, but was just wondering if someone could point me in the right direction right now instead of me having to spin my wheels.
Thanks a lot guys!
Try the following:
routes.MapRoute(
null, // optional route name
"faq",
new { controller="Home", action="Faq" } );
routes.MapRoute(
null, // optional route name
"Boxes/{boxnumber}",
new { controller="Boxes", action="Details", boxnumber = ""} );
// Original route, if needed, should come AFTER more specialized routes.
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } ); // Parameter defaults
Some notes that may help you understand this better:
the controller and action parameters must be specified, either explicitly in the incoming URL or via defaults that you specify (if missing in incoming URL)
the order of adding routes is significant because the first match will be used for each incoming URL. In the above example, if the original route is added first, the other ones will never be matched (because the original route specifies defaults for all parameterized parts of the URL)
route name is optional, only needed if you are using route names to generate outbound URLs
When you define a route, it has to at minimum contain two pieces of information: a controller and an action. Those values can either come through as a parameter (i.e. a "{parameter}" portion in the URL pattern), or as a default value.
The route example that you pasted above includes an action but it doesn't contain a controller, so it isn't capable of satisfying a request. Since your controller name is "BoxesController", you could simply add "controller='Boxes'" to the default values of that route and you'd be good.
To achieve the faq route, you could simply define a route whose URL was "faq" and had the default values: controller="Home", action="Faq".

Resources