Domanda

Sto usando MvcSiteMapProvider 2.2.1 (http://mvcsitemap.codeplex.com), e sto avendo un problema con la creazione di bambini al di sotto di un nodo dinamico (utilizzando un dynamicNodeProvider) quando questi bambini hanno un parametro dinamico (id).

sto perdendo il pangrattato per il seguente percorso:

Negozi / 5 / Prodotti / Modifica / 23

dove il modello url è:

Negozi / {storeID} / {Controller} / {action} / {id}

Funziona bene quando l'ID viene lasciato fuori (cioè l'azione "Nuovo"). Ma quando viene specificato l'ID, che non corrisponde al percorso, e le mie briciole di pane (utilizzando l'helper SiteMapPath) è vuoto.

Il mio sito: (abbreviati)

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

Area di registrazione:

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" }
        );
    }

primo tentativo:

La prima cosa che ho provato è stato quello di creare i nodi figlio proprio nel XML Sitemap come figli del nodo di dinamica. Questo non ha funzionato affatto, e questi ha finito per essere figli di "Home". Avrei messo un attributo ParentKey in là, tranne questi saranno ripetuti per punto vendita e, quindi, non ci sarà più 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>

secondo tentativo:

Mi sembrava l'opzione successiva è stato quello di aggiungere solo i nodi figlio proprio nel mio DynamicNodeProvider. Questo ha funzionato molto meglio, tranne per i nodi che avevano parametri dinamici

(il seguito è modificato per facilità di spiegazione ...)

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;
    }
}

In sintesi

funziona: Negozi / 5 / Prodotti / Nuovo
Non funziona: Negozi / 5 / Prodotti / Modifica / 23
Per Url Pattern: Negozi / {storeID} / {Controller} / {action} / {id}

Quello che mi piacerebbe essere in grado di fare:

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

Come faccio a mimare i vecchi dynamicParameters di MvcSiteMapProvider attribuiscono su un nodo che è un figlio di un dynamicNode? Fondamentalmente ho bisogno di ignorare il valore di percorso "id" quando corrispondenti percorsi.

Speriamo che ho spiegato che correttamente, e non ti ho sopraffare con le informazioni. Grazie!


UPDATE:

Ecco la soluzione che ha funzionato per me in base alla risposta di Jakub.

In MvcSiteMapProvider 2.x, è possibile effettuare la propria implementazione di ISiteMapNodeUrlResolver invece di dover modificare l'origine. Così ho praticamente aggiunto indietro nella capacità di avere l'attributo dynamicParameters

Classe:

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>

Dinamico nodo Provider:

DynamicNode node = new DynamicNode();
node.Attributes.Add("dynamicParameters", "id");
È stato utile?

Soluzione

Sto usando la versione 1.x. Ho avuto un problema simile con parametri dinamici.

ho dovuto modificare il codice sorgente - fatto un cambiamento in MvcSiteMapNode.cs. Questa è la nuova implementazione di proprietà 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;
        }
    }

Si noti come vengono aggiunti i valori effettivi di dynamicParameters alla raccolta routeValues.

La modifica di cui sopra mi ha permesso di definire paremteres dinamiche in sito (come 'id') e creare pangrattato con link come account / utente / Modifica / 23.

ho preso un breve sguardo alla versione 2.x e si dovrebbe essere in grado di applicare la patch simile. Spero che vi aiuterà a ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top