views:

421

answers:

2

Hi there,

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

+2  A: 

Try:

<%=Html.RouteLink("Test", "Default", new {controller = "Controller", action = "Action"})%>

Using RouteLink instead of ActionLink allows you to specify the route you want to use, which in this case is the Default MVC route mapping as opposed to the custom one you have added.

Stephen Lloyd
Hi thanks. I know RouteLink works, but it's just that tiny bit inconvenience! All the magic strings. Why doesn't ActionLink work.
rokeyge
It only contains one more string than ActionLink and your original question was "How do I construct a correct url?". The reason why this is necessary is that your WebFormRouteHandler provides a "valid" route match, and as it is added before your default route in the RouteTable it is returned first. But anyway, I've added another answer that may be more to your liking.
Stephen Lloyd
A: 

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.

Stephen Lloyd