Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Html.ActionLink construct wrong link when a non-mvc route is added

I have an application here with a mix of webform and mvc. I specify the routing as below

        routes.Add("AspxRoute", new Route("Upload/New", new WebFormRouteHandler<Page>("~/Uploads.aspx")));

        routes.MapRoute(
            "Default",                                              // Route name
            "{controller}/{action}/{id}",                           // URL with parameters
            new { controller = "Home", action = "Index", id = "" }  // Parameter defaults
        );   

So that virtual path to "Upload/New" actually maps to an aspx webform page.

But my problem is that Html.ActionLink("Test", "Controller", "Action") now renders

/Upload/New?Controller=Controller&Action=Action

Having looked at the MVC source code, I understand that it is because ActionLink calls to RouteCollection.GetVirtualPath(requestContext, routeName, mergedRouteValues), where routeName is left to null. And somehow this defaults to use the AspxRoute route to construct the url. I tried to added another route before "AspxRoute", but it seems it always defaults to the non-mvc routehandler one.

How does RouteCollection.GetVirtualPath behave when routeName is null? And why is it behaving this way for my case?

How do I construct a correct url? Do I need to write a new Htmlhelper extension?

Cheers

like image 509
Rokey Ge Avatar asked Sep 24 '09 11:09

Rokey Ge


People also ask

What is the difference between using URL action and HTML ActionLink in a view?

Yes, there is a difference. Html. ActionLink generates an <a href=".."></a> tag whereas Url. Action returns only an url.

What is HTML ActionLink in MVC?

Html. ActionLink creates a hyperlink on a view page and the user clicks it to navigate to a new URL. It does not link to a view directly, rather it links to a controller's action.

How do I change the default URL in MVC?

You can set up a default route: routes. MapRoute( "Default", // Route name "", // URL with parameters new { controller = "Home", action = "Index"} // Parameter defaults ); Just change the Controller/Action names to your desired default.

Can we map multiple URLs to the same action?

Yes, We can use multiple URLs to the same action with the use of a routing table. foreach(string url in urls)routes. MapRoute("RouteName-" + url, url, new { controller = "Page", action = "Index" });


1 Answers

An alternative option would be to add a custom constraint to your WebFormRoute(s). For example, you could create an implementation of IRouteConstraint to match RouteDirection.IncomingRequest, then use it to ensure the route is ignored by Server-Generated routes (such as ActionLink) but still used by client-generated requests. Something like:

public class IncomingOnlyRouteConstraint: IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        if (routeDirection == RouteDirection.IncomingRequest)
        {
            return true;
        }
        return false;
    }
}

And then add the constraint to your route:

routes.Add("AspxRoute", new Route("Upload/New", null, 
                            new RouteValueDictionary() { {"WebFormsConstraint", new IncomingOnlyRouteConstraint()} }, 
                            new WebFormRouteHandler<Page>("~/Uploads.aspx")));

Of course you may prefer to add your own style of constraint, this one is quite limiting on the route that implements it, but it's just an example of one way you could resolve the issue.

like image 92
Stelloy Avatar answered Sep 27 '22 20:09

Stelloy