visual tutorial studio net mvc microsoft framework asp c# asp.net asp.net-mvc asp.net-mvc-2 mvcsitemap

c# - tutorial - Creación de nodos secundarios para un DynamicNode en MvcSiteMapProvider que tienen parámetros dinámicos



mvc 5 download (1)

Estoy usando la versión 1.x. Tuve un problema similar con los parámetros dinámicos.

Tuve que modificar el código fuente: hice un cambio en MvcSiteMapNode.cs. Esta es la nueva implementación de la propiedad Url.

public override string Url { get { if (!string.IsNullOrEmpty(this.url)) return this.url; RequestContext ctx; if (HttpContext.Current.Handler is MvcHandler) ctx = ((MvcHandler)HttpContext.Current.Handler).RequestContext; else ctx = new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData()); var routeValues = new RouteValueDictionary(RouteValues); foreach (var key in DynamicParameters) routeValues.Add(key, ctx.RouteData.Values[key]); return new UrlHelper(ctx).Action(Action, Controller, routeValues); } set { this.url = value; } }

Observe cómo se agregan los valores reales de dynamicParameters a la colección routeValues.

El cambio anterior me permitió definir parámetros dinámicos en el mapa del sitio (como ''id'') y crear rutas de navegación con enlaces como Cuenta / Usuario / Editar / 23.

Eché un breve vistazo a la versión 2.x y deberías poder aplicar un parche similar. Espero que te ayude...

Estoy usando MvcSiteMapProvider 2.2.1 (http://mvcsitemap.codeplex.com), y estoy teniendo un problema con la creación de hijos en un nodo dinámico (usando un dynamicNodeProvider) cuando esos niños tienen un parámetro dinámico (id).

Estoy perdiendo migas de pan para la siguiente ruta:

Tiendas / 5 / Productos / Edición / 23

donde el patrón de url es:

Almacena / {storeID} / {controller} / {action} / {id}

Funciona bien cuando se omite la ID (es decir, la acción "Nueva"). Pero cuando se especifica el ID, no coincide con la ruta, y mi ruta de navegación (usando el ayudante de SiteMapPath) está en blanco.

Mi Sitemap: (abreviada)

<?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>

Registro de área:

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:

Lo primero que intenté fue crear los nodos secundarios en el xml del mapa del sitio como hijos del nodo dinámico. Esto no funcionó en absoluto, y estos terminaron siendo hijos de "Home". Yo pondría un atributo ParentKey allí, excepto que estos se repetirán por tienda y, por lo tanto, habrá varias claves principales

<?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 los nodos secundarios directamente en mi DynamicNodeProvider. Esto funcionó mucho mejor a excepción de los nodos que tenían parámetros dinámicos

(Se modifica a continuación 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

Funciona: Tiendas / 5 / Productos / Nuevo
No funciona: Tiendas / 5 / Productos / Edición / 23
Para el patrón de URL: Almacena / {storeID} / {controlador} / {acción} / {id}

Lo que me gustaría poder hacer:

editNode.Attributes.Add("isDynamic", "true"); editNode.Attributes.Add("dynamicParameters", "id");

¿Cómo puedo imitar el atributo dynamicParameters del antiguo MvcSiteMapProvider en un nodo que es un hijo de un nodo dinámico? Básicamente, lo necesito para ignorar el valor de ruta "id" cuando coincida con las rutas.

Ojalá lo expliqué correctamente y no te abrumé con información. ¡Gracias!

ACTUALIZAR:

Aquí está la solución que me funcionó basada en la respuesta de Jakub.

En MvcSiteMapProvider 2.x, puede hacer su propia implementación de ISiteMapNodeUrlResolver en lugar de tener que modificar la fuente. Así que básicamente volví a agregar la posibilidad 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>

Proveedor de nodo dinámico:

DynamicNode node = new DynamicNode(); node.Attributes.Add("dynamicParameters", "id");