MvcSiteMapProvider icon indicating copy to clipboard operation
MvcSiteMapProvider copied to clipboard

Urls not produced when you use a RouteAttribute instead of using routes.MapRoute()

Open johnwc opened this issue 7 years ago • 5 comments

If I decorate my controllers and actions with the Route attributes built into MVC, in place of manually building out the routes via routes.MapRoute(), the provider doesn't seem to find or use the routes. When using the Route attributes, the Url for each product we build with the dynamic node all have # as the value.

Dynamic Node

foreach(var prod in cat.Products)
{
    var prodNode = new DynamicNode();
    prodNode.Title = prod.Name;
    prodNode.ParentKey = catNode.Key;
    prodNode.Key = string.Format("Product_{0}", prod.Id);
    prodNode.Attributes.Add("visible", false);
    prodNode.Controller = "Product";
    prodNode.Action = "Index";
    prodNode.Route = "ProductInfo";
    prodNode.RouteValues.Add("id", prod.Id);
    prodNode.RouteValues.Add("producttitle", prod.Name);
}

Example not working:

public class RouteConfig
{
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapMvcAttributeRoutes();
            ...
        }
}

[RoutePrefix("product")]
public class ProductController : Controller
{
    // GET: product/123/pepsi
    [Route("{id}/{producttitle}", Name ="ProductInfo")]
    public ActionResult Index(int id)
    {
        ...
    }
}

Example working:

public class RouteConfig
{
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "ProductInfo",
                "product/{id}/{producttitle}",
                new { controller = "Product", action = "Index" }
                );
            ...
        }
}

public class ProductController : Controller
{
    // GET: product/123/pepsi
    public ActionResult Index(int id)
    {
        ...
    }
}

johnwc avatar Feb 22 '17 17:02 johnwc

What happens if you remove/comment the route name for the non-working example?

//prodNode.Route = "ProductInfo";

Attribute Routing support was added as a contribution to MvcSiteMapProvider after MVC 5 was released, and it is possible that some of the features of it aren't fully supported.

NightOwl888 avatar Feb 22 '17 18:02 NightOwl888

Has no affect, still doesn't work.

johnwc avatar Feb 23 '17 21:02 johnwc

If I call the Url.RouteUrl like so, it works. Is the code on the backend not calling Url.RouteUrl?

var url = new System.Web.Mvc.UrlHelper(HttpContext.Current.Request.RequestContext, System.Web.Routing.RouteTable.Routes);

foreach(var prod in cat.Products)
{
    var prodNode = new DynamicNode();
    prodNode.Title = prod.Name;
    prodNode.ParentKey = catNode.Key;
    prodNode.Key = string.Format("Product_{0}", prod.Id);
    prodNode.Attributes.Add("visible", false);
    prodNode.Controller = "Product";
    prodNode.Action = "Index";
    prodNode.Route = "ProductInfo";
    prodNode.RouteValues.Add("id", prod.Id);
    prodNode.RouteValues.Add("producttitle", prod.Name);
    prodNode.Url = url.RouteUrl("ProductInfo", new { id = prod.Id, producttitle = prod.Name });
}

johnwc avatar Mar 09 '17 15:03 johnwc

Any updates?

johnwc avatar Mar 26 '17 06:03 johnwc

So the issue turns out to be that the CurrentNode is always null when viewing a action that is created via attributes. I think I have traced it down to the FindSiteMapNodeFromMvcRoute method in the SiteMap.cs file. It looks like GetMvcRouteData returns the underlining route when contained in a RouteCollectionRoute, and then that value is passed to the FindSiteMapNodeFromMvcRoute. In FindSiteMapNodeFromMvcRoute it runs through all the routes on the RouteTable.Routes and checks to see if each is equal to the passed in Route. Since the RouteTable.Routes doesn't have the sub route in it's root list, it always equals false. It might need to be changed up so that it doesn't do a straight object == object, and maybe check the route path or something.

johnwc avatar Mar 29 '17 01:03 johnwc