#Url.Action("Action", "Controller") returns "/cgi-bin?action=Action&controller=Controller" - asp.net-mvc

For some reason it thinks the target is an Apache server - I suspect?
The MVC is V5.2.3 and its dependancies are correct as per nuget
. I have searched and searched to no avail.
EDIT
The code is simply #Url.Action("Action", "Controller")
So I created a brand new MVC project and using exactly the same code the correct code was returned.
http://localhost:53143/Controller/Action
EDIT 2
I removed my web.config files as the problem is not there.

I got in touch with an expert and he looked at the project and answered as below.
(BTW I have 'cgi-bin' in a route as there are old URLs out in the wild that relate to my domain previously being hosted on an Apache server and which I cannot change.)
The answer
I digged a little more into the source code of the mvc helpers and, yes, the two issues (I had a similar problem Html.BeginForm with overload causes form action to be '/cgi-bin?action=Index&controller=Home' and so the HomeController is bypassed) are related since Url.Action and Html.BeginForm boil down to calling one and the same method: UrlHelper.GetUrl... Now, what this method does is:
Retrieve the current URL including controller, action, area...
Add or replace the parameter(s) you specify,
Find the best matching route! <==
If there are any route variables - push the provided parameters into those variables.
Stick the rest of the parameters into the query string <==
I have deliberately highlighted point 3 & 5, with point 3 being the most important. So, UrlHelper.GetUrl (and Url.Action and Html.BeginForm respectively) needs a route and it searches through the available ones to find the first match.
Now, here comes the problem with your mixed webforms-mvc app - an issue which is not present when you are dealing purely with MVC: You are using MapPageRoute!!! Please, note that it is different from MapRoute. And MapPageRoute uses the PageRouteHandler class to create the route whereas MapRoute uses the MvcRouteHandler class and it makes all the difference because PageRouteHandler creates the route in such a way that it's always a good match for UrlHelper.GetUrl("ActionName", "ControllerName") with the action name and controller name being thrown into the query string as parameters (point 5).
So, what happens with your set-up is that Url.Action is searching for a route and is hitting the first one created by MapPageRoute and in your case this is:
routes.MapPageRoute("cgi-bin", "cgi-bin/{*theRestcgi-bin}", "~/home/Search.aspx");
That's where that arcane cgi-bin part of the query string comes from, giving the impression that the framework is actually searching for some virtual/physical folder.
As for the proper solution: either define a suitable route or specify the url as a simple string the way you have done. I think, your solution is the better one as you won't have to move around the route definitions in the RouteConfig class.

Related

Using optional parameters in Umbraco 7 Urls

Am new to using Umbraco. I need to create Urls with an an optional parameter on the end e.g.
mysite.com/people/john
mysite.com/people/jane
etc
however by default Umbraco appears to require a separate page for each person. Is there a built method in Umbraco that will allow me to define the last part of the Url as an optional parameter or do I have to write a custom route for it?
Thanks
You have a couple of options here.
Use IIS URL Rewriting to rewrite your URLs under the hood and rewrite /people/john to /people/?person=john say. Then you can pick up the person from the query string on the page.
Write a custom URL Finder that looks for the URLs and does some stuff under the hood, like get the people page, and then set a context item with the person name in for you to use in your views etc.
You could write a custom route for it. Custom routing in Umbraco is slightly different to in normal MVC. Here is a blog post detailing how you can do it: http://shazwazza.com/post/custom-mvc-routes-within-the-umbraco-pipeline/

MVC Routing - Generate the Route URL With Good Coding Standards

I'm learning how to do routing in MVC. It seems to me that the routing API only solves half the problem. I can easily see how to map incoming URLs to controller actions and params. However, it is not obvious to me how to generate these routed URLs in the source code of my pages.
For example, in one of my views, I use this code to get the route URL:
<a class="listingResult" href="#Url.RouteUrl("ListingSEO", new { id = Model.Listing.ID, seoName = ListingController.SeoName(Model.Listing.Title) })">
This seems like poor coding practice to me for several reasons:
If the route changes in the future, I may have many places in my View code that will need updating.
The View now requires knowledge of the ListingController (maybe this is not a big deal?)
I've lost strong typing on my input params, and if I misspell the param names, my code is broken, but this doesn't generate compile warnings.
How do I observe good coding standards when I am generating route URLs? The alternative seems to be putting static functions in the controller to generate routes, which would at least address concerns #1 and #3. If I worked with you and you saw the code above, how unhappy would you be?
My recommendations:
Generate URLs in the ViewModel, not the View: This will keep your views cleaner and logic free. You can pass the UrlHelper instance from the controller to the ViewModel, which will also help for my next point...
Use a strongly-typed URL generation technique: Such as delegate-based, expression-based or code generation.
One of the purposes of using named routes is to abstract the controller/action. Your named routes shouldn't really change. At the most, you'd just change the controller/action they hit, but that happens seamlessly behind the scenes because you're using named routes.
Your view requires knowledge of the controller because you've added a dependency on it. This is bad for a number of reasons. There's many different ways you could handle this that wouldn't require a dependency on the controller, depending on what it is you're actually doing here, but at the very least, you should simply use a utility class, so at least it wouldn't be controller-specific.
The route params are intentionally not strongly-typed, because routes are flexible by design. You can pass anything you want to the action, with or without a parameter to catch it (you can use something like Request to get at it without a param).

mvc route random number of parameters

I am trying to construct a route that routes to a specific product page.
The product exists in a category. Categories may also exist in categories. I am trying to construct the URL like
my-site.com/products/category/category/category/product
The amount of categories is able to change but the last parameter will always be the name of the product.
Is there any way to construct a route for this?
A solution exactly for you
I faced the same problem in the past and solved it a bit differently to what others will advise you here. Most of solutions will talk about *catch-all parameter. In your case this means that you'd have to parse the product out yourself. Manually. Because catch-all parameter may only be the last parameter in route definition.
Catch-all anywhere in the route
If you think of it carefully, you can actually realise that catch all parameter can actually be defined anywhere in the route as long as you have all other segments present. So I've written such route class that does all that and successfully runs in production on a heavy traffic website.
My blog post has all the information about it as well as all the code that will solve your problem:
Custom Asp.net MVC route class with catch-all segment anywhere in the URL
This makes it possible for you to define your route as:
products/{*categories}/{productId}
If you think of the catch-all parameter even further you could also get to the point that a single route definition could have several catch-all parameters as long as at least one segment between them is static. But my class isn't able to do this, because your scenario with just one arbitrary segment set is much more common.

ASP.NET MVC AnchorLink not using route values?

I'm using AnchorLink on a very simple site with just two routes defined, one standard route and another area route for admin/{controller}/{action}/{id}. I'm at a URL like:
/admin/release/push/255
In that view I'm using:
#Html.AnchorLink("Confirm", "Confirm")
AnchorLink is rendering a link without the current request {id} included, ie. /admin/release/confirm! If I inspect the RouteValues I can see {id} is in there. If I explicity pass in the route values from teh current request, as in:
#Html.AnchorLink("Confirm this release", "Confirm", Url.RequestContext.RouteData.Values)
Then it works, I get the URL /admin/release/confirm/255. Why does the explicit version where I pass in the current request route values work, but the implicit one, without the route values argument, which I thought would pick up the current request route values, doesn't? I know the above is a solution, but it's ugly and there's some underlying reason why the AnchorLink without the route values isn't working as I expect?!
MVC is doing exactly the right thing here. It's not to know you require the Id parameter for your anchor link or not -- in other words its not trying anything clever to pre-parse and examine the link. It will only do that when its being rendered. And in your case without the id parameter specified somewhere its going to use the default route.
If you find yourself writing that same code all over the place you could easily extract it out into a static helper class. That can get rid of the ugliness.

How to make ASP.NET MVC create lowercase urls (action links)?

I know this question has been asked many times. But people suggest creating custom derived route classes, or writing lowercase everywhere in code (for action links) which is a really dirty way (what if I just decide to make'em all Pascal Cased again? changing hundreds of links?), or they suggest to create HTML helpers to do that (which is not a bad answer). But isn't there a more simple way? I mean something like setting some configuration in web.config file, or using an HttpModule or something else which is both simple, and centralized?
Apart from the options you have already listed, I can think of no other way of producing this result.
In short, the URL needs to be processed by 'something', be it .ToLower(), a Helper Method or HTTPModule.
In most of our applications, we use a Global Static method that performs actions on the desired URI and returns the result.
The following will allow that.. http://mvccoderouting.codeplex.com/ - and much more besides.

Resources