Estoy usando MvcSiteMapProvider 2.2.1 (http://mvcsitemap.codeplex.com) y tengo un problema al crear elementos secundarios en un nodo dinámico (utilizando un DynamicNodeProvider) cuando esos niños tienen un parámetro dinámico (id).Creación de nodos secundarios para un DynamicNode en MvcSiteMapProvider que tienen parámetros dinámicos
estoy perdiendo el pan rallado para el siguiente recorrido:
Tiendas/5/Productos/Editar/23
donde el patrón de URL es:
Tiendas/{storeID}/{ controller}/{action}/{id}
Funciona bien cuando el ID se deja fuera (es decir, la acción "Nuevo"). Pero cuando se especifica el ID, no coincide con la ruta y mis rutas de exploración (usando el ayudante SiteMapPath) están en blanco.
Mi mapa del sitio: (abreviated)
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-2.0">
<mvcSiteMapNode title="Home" controller="Dashboard" action="Index" changeFrequency="Always" updatePriority="Normal">
<mvcSiteMapNode title="My Account" controller="Account" action="Index" key="Account" />
<mvcSiteMapNode title="My Stores" area="Stores" controller="Home" action="Index" visibilityProvider="ControlPanel.Areas.Stores.StoreAreaVisibilityProvider, ControlPanel" >
<mvcSiteMapNode title="Store" action="Index" dynamicNodeProvider="ControlPanel.Areas.Stores.StoreAreaNodeProvider, ControlPanel" />
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMap>
Área de Registro:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Store_Index",
"Stores",
new { action = "Index", controller = "Home" },
new string[] { "ControlPanel.Areas.Stores.Controllers" }
);
context.MapRoute(
"Store_default",
"Stores/{storeID}/{controller}/{action}/{id}",
new { action = "Index", controller = "Manage", id = UrlParameter.Optional },
new { storeID = @"\d+" },
new string[] { "ControlPanel.Areas.Stores.Controllers" }
);
}
primer intento:
La primera cosa que probé era crear el niño nodos justo en el mapa del sitio xml como niños del nodo dinámico Esto no funcionó en absoluto, y estos terminaron siendo hijos de "Hogar". Me puse un atributo ParentKey allí, excepto éstos se repetirán por tienda y por tanto habrá múltiples parentkeys
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-2.0">
<mvcSiteMapNode title="Home" controller="Dashboard" action="Index" changeFrequency="Always" updatePriority="Normal">
<mvcSiteMapNode title="My Account" controller="Account" action="Index" key="Account" />
<mvcSiteMapNode title="My Stores" area="Stores" controller="Home" action="Index" visibilityProvider="ControlPanel.Areas.Stores.StoreAreaVisibilityProvider, ControlPanel" >
<mvcSiteMapNode title="Store" action="Index" dynamicNodeProvider="ControlPanel.Areas.Stores.StoreAreaNodeProvider, ControlPanel">
<mvcSiteMapNode title="Products" area="Stores" controller="Products" action="Index">
<mvcSiteMapNode title="Edit" area="Stores" controller="Products" action="Edit"/>
<mvcSiteMapNode title="New" area="Stores" controller="Products" action="Edit"/>
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMap>
segundo intento:
parecía que la siguiente opción era simplemente agregar el niño nodos directamente en mi DynamicNodeProvider. Esto funcionó mucho mejor a excepción de los nodos que tenían parámetros dinámicos
(el siguiente es modificado para facilitar la explicación ...)
public class StoreAreaNodeProvider : IDynamicNodeProvider
{
public IEnumerable<DynamicNode> GetDynamicNodeCollection()
{
var nodes = new List<DynamicNode>();
foreach (var store in repo.GetStores())
{
DynamicNode node = new DynamicNode();
node.Title = store.Name;
node.Area = "Stores";
node.Controller = "Manage";
node.Action = "Index";
node.RouteValues.Add("storeID", store.StoreID);
node.Key = "Store_" + store.StoreID.ToString();
nodes.Add(node);
//Child of node
DynamicNode productsNode = new DynamicNode();
productsNode.Title = "Products";
productsNode.Area = "Stores";
productsNode.Controller = "Products";
productsNode.Action = "Index";
productsNode.RouteValues.Add("storeID", store.StoreID);
productsNode.ParentKey = String.Format("Store_{0}", store.StoreID.ToString());
productsNode.Key = String.Format("Store_{0}_Products", store.StoreID.ToString());
nodes.Add(productsNode);
//child of productsNode
DynamicNode editNode = new DynamicNode();
editNode.Title = "Edit";
editNode.Area = "Stores";
editNode.Action = "Edit";
editNode.Controller = "Products";
editNode.RouteValues.Add("storeID", store.StoreID);
//I can't add the RouteValue "ID" here because it is dynamic
//I would have do loop through every product for this store with
//another dynamic node provider, but that seems terribly inefficient and stupid
editNode.ParentKey = String.Format("Store_{0}_Products", store.StoreID.ToString());
editNode.Attributes.Add("visibility", "SiteMapPathHelper,!*");
nodes.Add(editNode);
}
return nodes;
}
}
En resumen
hace el trabajo: Tiendas/5/Productos/Nuevos
no funciona: Tiendas/5/Productos/Editar/23
Por patrón de URL: Tiendas/{storeID}/{controlador}/{acción}/{id}
Lo que me gustaría ser capaz de hacer:
editNode.Attributes.Add("isDynamic", "true");
editNode.Attributes.Add("dynamicParameters", "id");
¿Cómo puedo imitar dynamicParameters del viejo MvcSiteMapProvider atribuyen en un nodo que es hijo de un dynamicNode? Básicamente, necesito que ignore el valor de la ruta "id" cuando coinciden las rutas.
Afortunadamente lo expliqué correctamente y no te abrumé con información. ¡Gracias!
ACTUALIZACIÓN:
Aquí está la solución que trabajó para mí en base a la respuesta de Jakub.
En MvcSiteMapProvider 2.x, puede realizar su propia implementación de ISiteMapNodeUrlResolver en lugar de tener que modificar la fuente. Así que, básicamente, vuelve a añadir en la capacidad de tener el atributo dynamicParameters
Clase:
namespace ControlPanel
{
public class CustomSiteMapNodeUrlResolver : ISiteMapNodeUrlResolver
{
public virtual string ResolveUrl(MvcSiteMapNode mvcSiteMapNode, string area, string controller, string action, IDictionary<string, object> routeValues)
{
RequestContext ctx;
if (HttpContext.Current.Handler is MvcHandler)
ctx = ((MvcHandler)HttpContext.Current.Handler).RequestContext;
else
ctx = new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData());
//Begin Added Code
if (mvcSiteMapNode["dynamicParameters"] != null)
{
foreach (var item in mvcSiteMapNode["dynamicParameters"].Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
var dp = item.Trim();
routeValues[da] = ctx.RouteData.Values[dp];
}
}
//End Added Code
return new UrlHelper(ctx).Action(action, controller, new RouteValueDictionary(routeValues));
}
}
}
Web.config:
<siteMap defaultProvider="MvcSiteMapProvider" enabled="true">
<providers>
<clear/>
<add name="MvcSiteMapProvider"
type="MvcSiteMapProvider.DefaultSiteMapProvider, MvcSiteMapProvider"
siteMapFile="~/Mvc.Sitemap"
securityTrimmingEnabled="true"
attributesToIgnore="visibility,dynamicParameters"
scanAssembliesForSiteMapNodes="true"
siteMapNodeUrlResolver="ControlPanel.CustomSiteMapNodeUrlResolver, ControlPanel"
siteMapNodeVisibilityProvider="MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider" />
</providers>
</siteMap>
dinámico de nodo del proveedor:
DynamicNode node = new DynamicNode();
node.Attributes.Add("dynamicParameters", "id");
Ahora es 2012, estoy usando la versión 3.x y sigo teniendo el mismo problema. –
Y el problema es que el método ResolveUrl personalizado se ejecuta tan pronto como se inicia la aplicación (sin navegar a esa página parametrizada), por lo que la línea que está obteniendo el parámetro de ruta actual ctx.RouteData.Values [dp] es nula, por lo que no es Es posible reemplazar el parámetro de ruta del mapa del sitio con el parámetro de ruta actual. ¿Algunas ideas? –
Hola @AlperOzcetin, no he tocado este código en tanto tiempo, no tengo ni idea. Y en realidad, unos meses después de esta publicación, este proyecto evolucionó lo suficiente como para que MvcSiteMapProvider no lo hiciera por mí, y terminamos lanzando nuestra propia solución desde cero (que el sitio aún ejecuta hoy). Buena suerte ... –