开发者

Unable to make ActionLink or RouteLink generate the correct URL

I'm new to ASP.NET MVC (working with version 3) and cannot get ActionLink or RouteLink to work as I'm expecting. In this app, an event can have many activities and I wish to route to them using:

/Event/1/Activity
/Event/1/Activity/Index  (same as previous)
/Event/1/Activity/Details/5

The HTML generated by these two helpers always looks like:

/Event/1

Here's the code...

View Razor HTML

@Html.RouteLink("View Sessions", "SubControllerIndex",
    new { eventId = Model.Id, controller = "Activity", action = "Index" })
@Html.ActionLink("View Sessions", "Index", "Activity", new开发者_开发问答 { eventId = Model.Id }, null)

Route mappings

routes.MapRoute(
    "SubControllerIndex",
    "Event/{eventId}/{controller}",
    new { controller = "Activity", action = "Index" },
    new { eventId = @"\d+" }
);
routes.MapRoute(
    "ActivityIndex",
    "Event/{eventId}/{controller}/{action}/{id}",
    new { controller = "Activity", action = "Index", id = UrlParameter.Optional },
    new { eventId = @"\d+", id = @"\d*" }
);
routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
    new { id = @"\d*" }
);

Activity controller

public ActionResult Index(long eventId)
{
    var activities = _context.Activities.Where(a => a.Event.Id == eventId).ToList();
    return View(activities);
}

Any ideas what I'm doing wrong here?


The reason that the routing system generates /Event/1 instead of /Event/1/Activity/Index for the route

routes.MapRoute(
   "ActivityIndex",
   "Event/{eventId}/{controller}/{action}/{id}",
   new { controller = "Activity", action = "Index", id = UrlParameter.Optional },
   new { eventId = @"\d+", id = @"\d*" }
);

is because when generating urls the system will not include any default values in the url. In this case the default value of controller is Activity and the default value of action is Index. Thus,

@Html.RouteLink("View Sessions", "SubControllerIndex",
    new { eventId = Model.Id, controller = "Activity", action = "Index" })

will generate /Event/1 instead of /Event/1/Activity/Index. If you click on the link you should still go to the Index action method on the ActivityController.


As mrydengren points out, the ActionLink and RouteLink methods will strip out the parameters that are the same as the defaults. The URLs should then point to the action you're pointing to.

If you still would like to use the full URL, you could create a route without the default values and use RouteLink to create your links with that route.

// Either add this at the end as a new route, or replace the one you already have.
routes.MapRoute("ActivityIndexWithoutParams",
    "Event/{eventId/controller/action/id},
    new{},
    new{ eventId = @"\d+", id = @"\d*"}
    );

Now you can use the RouteLink method to create the correct route:

@Html.RouteLink("View Sessions", "ActivityIndexWithoutParameters",
    new {eventid = Model.Id, controller = "activity", action = "index"}
    );


I ran across this when trying (and trying and trying) to find an answer to why my custom RouteBase implementations were not working on outbound routes (the ones that generate URLs) when I switched the project to using areas.

I finally stumbled on the answer while analyzing the MVC source code: you have to make your custom RouteBase implementations implement IRouteWithArea so the framework knows which Area your custom routes belong to.

public class CustomRoute: RouteBase, IRouteWithArea
{
    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
         // Implement custom virtual path (url) here
    }

    #region IRouteWithArea Members

    public string Area
    {
        get { return "Store"; }
    }

    #endregion
}


Remember that routes are 'greedy', and the first match will be the one that gets processed, so you need to lose that first route entry, otherwise the second one will never be reached.

That's the only change I can see you need to make, it's fine otherwise, add an action link to a view as follows;

@Html.ActionLink("View Sessions", "Details", "Activity", new { eventId = 12, id = 22 }, null)

And you should see that generates the correct URL in the link.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜