Added a route and the behaviour changed - asp.net-mvc

I would like to optimize the appearance of the URL like below:
http://localhost:3817/Affaire/SearchAffaires?OnlyFavorite=True
So I added a new route:
routes.MapRoute(
"Search Affaire Only Favorite", // Route name
"{controller}/{action}/OnlyFavorite", // URL with parameters
new { controller = "Affaire", action = "SearchAffaires", OnlyFavorite = true } // Parameter defaults
);
Now the URL is easier to read:
http://localhost:3817/Affaire/SearchAffaires/OnlyFavorite
But a new problem is occured: the other links on my page have changed because of the routing!
Example here: .../Affaire/SearchAffaires?LabelName=Baxter&OnlyLabel=True&OnlyFavorite=True
Before it was: .../Affaire/SearchAffaires?LabelName=Baxter&OnlyLabel=True
As you can see, the variable OnlyFavorite has been added to the URL. Finally I found the reason of this behaviour: the routing system is keen to make a match against a route, to the extent that it will reuse segment variable values from the incoming URL. The best way to deal with this behavior is to prevent it from happening. It is strongly recommend that you
do not rely on this behaviour, and that you supply values for all of the segment variables in a URL pattern.
That's a little bit annoying because I have a lot of variables!
Any solution on that problem? Why is that behaviour not happening whith one single route (the default one)?
Thanks

It looks like if I've registering routes like this, i get away from problem:
routes.MapRoute(
"Search Affaire", // Route name
"{controller}/{action}", // URL with parameters
new { controller = "Affaire", action = "SearchAffaires" } // Parameter defaults
);
routes.MapRoute(
"Search Affaire Only Favorite", // Route name
"{controller}/{action}/OnlyFavorite", // URL with parameters
new { controller = "Affaire", action = "SearchAffaires", OnlyFavorite = true } // Parameter defaults
);

Related

If action name found then call action, if not call a default action in MVC Routing

this is my current routing
routes.MapRoute(
"Default", // Route name
"{action}/{id}", // URL with parameters
new { controller = "MarketingSite", action = "index", id = "" } // Parameter defaults
);
so whenever I visit domain.com/test
This would invoke the test action in the controller called MarketingSite.
What I want to achieve is when I visit domain.com/load-from-db and since I don't have an action called load-from-db, I want to direct the request to a specific action and load-from-db becomes the parameter for that action. In that action, i'm going to read something from the database based on the parameter and then return a view. If I specify an action that exist, then it would just call that action.
Any help?
First note - the routing engine will apply the routes in the order you list them, checking each, and continuing if it cannot match. You currently have the "default" route setup as a catch-all - if is doesn't find a controller it uses "MarketingSite", if there is no action it uses "index". If I am understanding your problem, you don't want an "Index" action at all, you want to call another action, and pass the query to that.
You could try:
//Look for a matching action
routes.MapRoute(
"MatchAction", // Route name
"{action}/{id}",
new { controller = "MarketingSite", id = UrlParameter.Optional}
);
//With a single segment, pass that to a specific action as a parameter.
routes.MapRoute(
"load-from-db", // Route name
"{load-from-db}", // URL with parameters
new { controller = "MarketingSite", action = "MyAction"}
);
//With no segments (ex. domain.com/) use the Index on MarketingSite as default.
routes.MapRoute(
"Default", // Route name
"", // URL with parameters
new { controller = "MarketingSite", action = "Index"}
);
However, these routes might not accomplish exactly what you are looking for - getting your routes mapped in MVC can be a bit tricky. You should check this this out, and design your routes accordingly.
Hope that helps,
Chris
Override the HandleUnknownAction method on the MarketingSite controller:
protected override void HandleUnknownAction(string actionName) {
// TODO: check for actionName in database
}

Routing and reflection problem

I added routing to my solution in order to have a more user friendly URL in the address bar.
I start the solution and when I rollover my Favorites link, I see the URL .../Affaire/Favorite (picture below). This one is OK for me.
When I rollover my Recycle bin link, I see the URL ../Affaire/Deleted (picture below). This one is OK for me.
Then I click on the Recycle bin link, I navigate to the corresponding page and the URL showed in the address bar is OK for me (picture below).
Next, I rollover the Favorite link again (picture below), I see the URL ../Affaire/Delete?OnlyFavorite=true!! That's not OK.
The routing is now retrieving an attribute not from my link but from the active URL! This attribute is named OnlyFavorite and I don't want this attribute. This is the "reflexion". Notice that all of my routes are using the same controller and the same action but using different attributes for the routes.
Below are some links I used.
Example for navigating to the favorite page:
#Html.ActionLink("Favorites", "SearchAffaires", new { OnlyFavorite = true })
Example for navigating to the recycle bin page:
#Html.ActionLink("Recycle bin", "SearchAffaires", new { StatusCode = "DELETED" })
Here are my routes:
routes.MapRoute(
"Affaire Status Open/Closed/Deleted", // Route name
"{controller}/{StatusCode}", // URL with parameters
new { action = "SearchAffaires" }, // Parameter defaults
new { controller = "Affaire", StatusCode = "^Open$|^Closed$|^Deleted$" }// Contraints
);
routes.MapRoute(
"Affaire Only Favorite", // Route name
"{controller}/Favorite", // URL with parameters
new { action = "SearchAffaires", Page = 1, OnlyFavorite = true }, // Parameter defaults
new { controller = "Affaire" } // Contraints
);
Do you have any idea how can I proceed to avoid this behaviour?
I don't want the routing to get the attribute named OnlyFavorite from my current URL by reflexion. I already try to pass OnlyFavorite=null on the action link but it doesn't work: the routing says "ok, I don't have a value for OnlyFavorite on the link itself but I have OnlyFavorite on the URL so I use it!".
When you are on the Deleted page, the link is being processed that way because the StatusCode token is equal to Deleted, so the first route is satisfied. Change your link as follows:
#Html.ActionLink("Favorites", "SearchAffaires", new { StatusCode = String.Empty, OnlyFavorite = true })
UPDATED
The best solution is to reverse your routes. As a general rule, the most specific routes should always go first, and you should have more generic routes later. Since the "Affaire Only Favorite" route is more specific, it should always go first. If it is the first route satisfied, that should address your issue.
UPDATE #2
I ran a test, and all of the links were generated correctly, when I set the routes as follows:
routes.MapRoute(
"Affaire Only Favorite", // Route name
"Affaire/Favorite", // URL with parameters
new { controller = "Affaire", action = "SearchAffaires",
StatusCode = String.Empty, Page = 1, OnlyFavorite = true } // Parameter defaults
);
routes.MapRoute(
"Affaire Status Open/Closed/Deleted", // Route name
"{controller}/{StatusCode}", // URL with parameters
new { action = "SearchAffaires" }, // Parameter defaults
new { controller = "Affaire", StatusCode = "^Open$|^Closed$|^Deleted$" } // Constraints
);
In addition, the following more generic routes also generated correctly:
routes.MapRoute(
"Favorite", // Route name
"{controller}/Favorite", // URL with parameters
new { action = "Search",
StatusCode = String.Empty, Page = 1, OnlyFavorite = true } // Parameter defaults
);
routes.MapRoute(
"Status Open/Closed/Deleted", // Route name
"{controller}/{StatusCode}", // URL with parameters
new { action = "Search" }, // Parameter defaults
new { StatusCode = "^Open$|^Closed$|^Deleted$" } // Constraints
);
For the more generic routes to work, I had to rename the action as Search and I had to change each link from SearchAffaires to Search.
Well, you could use Html.RouteLink helper to point exactly to the route used. However, as #counsellorben pointed out, you should set your more specific route to be the first one.
And if there's no problem to show your url like "Affaire/Favorite/True", then you can use the example below:
routes.MapRoute(
"Affaire Only Favorite", // Route name
"{controller}/Favorite/{OnlyFavorite}", // URL with parameters
new { action = "SearchAffaires", Page = 1, OnlyFavorite = ""}, // Parameter defaults
new { controller = "Affaire" } // Contraints
);

Can I constrain a route parameter to a certain type in ASP.net MVC?

I have the following route:
routes.MapRoute(
"Search", // Route name
"Search/{affiliateId}", // URL with parameters
new { controller = "Syndication", action = "Search" } // Parameter defaults
);
Is there a way I can ensure "affiliateId" is a valid Guid? I'm using MVCContrib elsewhere in my site and I'm fairly it provides a way to implement this kind of constraint.... I just don't know what it is!
You could write regex constraints:
routes.MapRoute(
"Search", // Route name
"Search/{affiliateId}", // URL with parameters
new { controller = "Syndication", action = "Search" }, // Parameter defaults
new { affiliateId = "SOME REGEX TO TEST GUID FORMAT" } // constraints
);
I've never heard of this. I fear it would cause some confusion if you mistakenly used the wrong type for the affiliateId parameter in one of your action methods.

ASP.NET MVC - Routes and UrlHelper

I have the following route
routes.MapRoute(
"GigDayListings", // Route name
"gig/list/{year}/{month}/{day}", // URL with parameters
new { controller = "Gig", action = "List" },
new
{
year = #"^[0-9]+$",
month = #"^[0-9]+$",
day = #"^[0-9]+$"
} // Parameter defaults
);
When I visit the URL
gig/list/2009/01/01
This route matches perfectly and my action is called.
Inside my view I have a helper which does the following:
var urlHelper = new UrlHelper(ViewContext);
string url = urlHelper.RouteUrl(ViewContext.RouteData.Values);
The string generated is:
http://localhost:3539/gig/list?year=2005&month=01&day=01
Why is it not
http://localhost:3539/gig/list/2005/01/01
What am I doing wrong?
I think your problem is that you didn't specify the route name in your call. Try to use
UrlHelper.RouteUrl(**"GigDayListings"**, ViewContext.RouteData.Values);
overload with route name.
Cheers!
Have you checked that when you supply gig/list/2008/01/01 that it is actually using the GigDayListings route? Maybe it's using a different one

Creating urls with asp.net MVC and RouteUrl

I would like to get the current URL and append an additional parameter to the url (for example ?id=1)
I have defined a route:
routes.MapRoute(
"GigDayListings", // Route name
"gig/list/{year}/{month}/{day}", // URL with parameters
new { controller = "Gig", action = "List" } // Parameter defaults
);
In my view I have a helper that executes the following code:
// Add page index
_helper.ViewContext.RouteData.Values["id"] = 1;
// Return link
var urlHelper = new UrlHelper(_helper.ViewContext);
return urlHelper.RouteUrl( _helper.ViewContext.RouteData.Values);
However this doesnt work.
If my original URL was :
gig/list/2008/11/01
I get
gig/list/?year=2008&month=11&day=01&id=1
I would like the url to be:
controller/action/2008/11/01?id=1
What am I doing wrong?
The order of the rules makes sence. Try to insert this rule as first.
Also dont forget to define constraints if needed - it will results in better rule matching:
routes.MapRoute(
"GigDayListings", // Route name
"gig/list/{year}/{month}/{day}", // URL with parameters
new { controller = "Gig", action = "List" }, // Parameter defaults
new
{
year = #"^[0-9]+$",
month = #"^[0-9]+$",
day = #"^[0-9]+$"
} // Constraints
);

Resources