views:

200

answers:

3

I'm trying to create twitter.com/rob to go to a dynamic page (using account/viewuser) as well as allowing twitter.com/help to go to a help page (help/index).

The below code doesn't work in either order because the Default route handler always picks up ID as controller because controller/action/id are all optional.

Is there any way to do this without defining every page in the website up front in the global.asax.cs?


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

        routes.MapRoute(
            "UserHomepage",                                               // Route name
            "{id}",                                                       // URL with parameters
            new { controller = "Account", action = "ViewUser", id = "" }  // Parameter defaults
        );
+2  A: 

you can put the second route ("UserHomePage") before Default. The routes are evaluated in the order they appear in the code.

That said, currently http://yoursite/ goes to http://yoursite/Home/Index and if you make the suggested change, it will go to http://yoursite/Account/ViewUser (I am not clear what Twitter has to do with this). You need to decide what is desired behavior, and design the routes accordingly

Felix
This was my first thought, but as you said, the homepage dies. Twitter is an example of the behaviour I want.
Rob Ellis
A: 

You could add the none user routes before you add the user account route. Ex

routes.MapRoute(
            "About",                                               
            "About/{id}",                                                       
            new { controller = "About", action = "Index", id = "" }  
        );

routes.MapRoute(
            "Home",                                               
            "About/{id}",                                                       
            new { controller = "Home", action = "Index", id = "" }  
        );

routes.MapRoute(
        "UserHomepage",                                               
        "{id}",                                                       
        new { controller = "Account", action = "ViewUser", id = "" }  
    );
Carl Bergquist
Hi Carl - this means I have to define all controllers. This is my backup plan!
Rob Ellis
+1  A: 

Put the "UserHomepage" route first. Then it should do it as what @Felix has explained above. As much as possible, make your default route at the end.

But its tricky. You need to add constraints to it because that route will trigger even if what you supplied is the controller name. e.g.

if you have http://yoursite.com/home we expect this to go to your "home/index" as what is defined on the default route. But the UserHomepage route comes first before the default so what we expect will not happen, instead http://yoursite.com/home will go to "account/viewuser/home" treating home as the id.

A solution to this is to define a constraint.

What i did is define a constraint class

Public Class UserNameConstraint
    Implements IRouteConstraint

    Public Function Match(ByVal httpContext As System.Web.HttpContextBase, ByVal route As System.Web.Routing.Route, ByVal parameterName As String, ByVal values As System.Web.Routing.RouteValueDictionary, ByVal routeDirection As System.Web.Routing.RouteDirection) As Boolean Implements System.Web.Routing.IRouteConstraint.Match
        Dim list As New List(Of String)
        list.Add("home") 'List of controller names

        For Each item In list
            If values("id").ToString() = item Then
                Return False
            End If
        Next

        Return True
    End Function
End Class

After defining the constraint change your route to include the constraint

 routes.MapRoute( _
            "UserHomepage", _
            "{id}", _
            New With {.controller = "Case", .action = "FriendlyName"}, _
            New With {.id= New UserNameConstraint()} _
       )

This route now will disregard if the id is listed on the list on the constraint.

Thats it. Hope you understand. :)

mcxiand
Took a while to get my head around! I'm trying to get the least configuration really. What about adding:- routes.MapRoute( "Homepage", // Route name "", // URL with parameters new { controller = "Home", action = "Index", id = "" } // Parameter defaults );
Rob Ellis