首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MVC SiteMapProvider dynamicNode可以在1层使用吗?

MVC SiteMapProvider dynamicNode可以在1层使用吗?
EN

Stack Overflow用户
提问于 2015-10-15 22:22:52
回答 2查看 231关注 0票数 1

我已经和MVC SiteMapProvider混了一段时间了,我很喜欢它。我正在建设一个电子商务网站,到目前为止,它在我的开发过程中运行得很好。

有一个问题我似乎无法解决,那就是如何让dynamicNode在第一级工作。

就像这样:

代码语言:javascript
复制
www.mysite.com/{type}/{category}/{filter}

只有3种类型,所以现在我只有3个控制器以该类型命名,它们都使用相同的逻辑和viewModels,这并不是理想的可维护性设置。我的routeConfig包括三条这样的路线。

代码语言:javascript
复制
routes.MapRoute(
            name: "Hardscape",
            url: "hardscape-products/{category}/{filter}",
            defaults: new { controller = "Products", action = "Index", category = UrlParameter.Optional, filter = UrlParameter.Optional},
            namespaces: new[] { "MyApp.Web.Controllers" }
        );

routes.MapRoute(
            name: "Masonry",
            url: "masonry-products/{category}/{filter}",
            defaults: new { controller = "Products", action = "Index", category = UrlParameter.Optional, filter = UrlParameter.Optional},
            namespaces: new[] { "MyApp.Web.Controllers" }
        );

routes.MapRoute(
            name: "Landscape",
            url: "landscape-products/{category}/{filter}",
            defaults: new { controller = "Products", action = "Index", category = UrlParameter.Optional, filter = UrlParameter.Optional},
            namespaces: new[] { "MyApp.Web.Controllers" }
        );

我尝试过这样的方法,但它返回404。

代码语言:javascript
复制
   routes.MapRoute(
            name: "Products",
            url: "{productType}/{category}/{filter}",
            defaults: new { controller = "Products", action = "Index", productType = UrlParameter.Optional,  category = UrlParameter.Optional, filter = UrlParameter.Optional},
            namespaces: new[] { "MyApp.Web.Controllers" }
        );

我已经能够在站点地图和菜单中为我的类别和过滤器参数使用dynamicNode生成我的节点。只是在没有静态命名第一级的时候遇到了第一级的麻烦

代码语言:javascript
复制
masonry-products/ vs. {productType}/

如果你有解决办法,请告诉我。希望NightOwl能加入进来。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-10-16 18:23:42

.NET的路由框架非常灵活。

对于这种情况,只需对类型使用约束即可。有两种方式:

  1. 使用RegEx
  2. 实现自定义类

如果您没有预料到大量的更改,那么第一个选项就不会那么糟糕了:

代码语言:javascript
复制
routes.MapRoute(
    name: "Products",
    url: "{productType}/{category}/{filter}",
    defaults: new { controller = "Products", action = "Index", category = UrlParameter.Optional, filter = UrlParameter.Optional},
    constraints: new { productType = @"hardscape-products|masonry-products|landscape-products" },
    namespaces: new[] { "MyApp.Web.Controllers" }
);

第二种选择更具动态性:

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;

public class ProductTypeConstraint : IRouteConstraint
{
    private object synclock = new object();

    public bool Match
        (
            HttpContextBase httpContext,
            Route route,
            string parameterName,
            RouteValueDictionary values,
            RouteDirection routeDirection
        )
    {
        return GetProductTypes(httpContext).Contains(values[parameterName]);
    }

    private IEnumerable<string> GetProductTypes(HttpContextBase httpContext)
    {
        string key = "ProductTypeConstraint_GetProductTypes";
        var productTypes = httpContext.Cache[key];
        if (productTypes == null)
        {
            lock (synclock)
            {
                productTypes = httpContext.Cache[key];
                if (productTypes == null)
                {
                    // TODO: Retrieve the list of Product types from the 
                    // database or configuration file here.
                    productTypes = new List<string>()
                    {
                        "hardscape-products",
                        "masonry-products",
                        "landscape-products"
                    };

                    httpContext.Cache.Insert(
                        key: key,
                        value: productTypes,
                        dependencies: null,
                        absoluteExpiration: System.Web.Caching.Cache.NoAbsoluteExpiration,
                        slidingExpiration: TimeSpan.FromMinutes(15),
                        priority: System.Web.Caching.CacheItemPriority.NotRemovable,
                        onRemoveCallback: null);
                }
            }
        }

        return (IEnumerable<string>)productTypes;
    }
}

缓存在这里是必要的,因为每个请求都会受到约束。

代码语言:javascript
复制
routes.MapRoute(
    name: "Products",
    url: "{productType}/{category}/{filter}",
    defaults: new { controller = "Products", action = "Index", category = UrlParameter.Optional, filter = UrlParameter.Optional},
    constraints: new { productType = new ProductTypeConstraint() },
    namespaces: new[] { "MyApp.Web.Controllers" }
);

当然,这不是唯一的动态选择。如果您真的需要选择您选择的任何URL,比如在CMS中,您可以从数据库中继承RouteBase并驱动您的所有URL。

不过,不确定这个问题与动态节点提供程序有什么关系。我也不明白“第一级”是什么意思。

对于动态节点提供程序,唯一真正需要做的事情就是匹配路由中的相同路由值,并提供密钥-父密钥关系。必须在XML或.NET属性中定义一个父键,以便从提供程序上附加顶级节点。

路由

代码语言:javascript
复制
dynamicNode.Controller = "Product";
dynamicNode.Action = "Index";
dynamicNode.RouteValues.Add("productType", "hardscape-products");
dynamicNode.RouteValues.Add("category", "some-category");
dynamicNode.RouteValues.Add("filter", "some-filter");

代码语言:javascript
复制
dynamicNode.Controller = "Product";
dynamicNode.Action = "Index";
dynamicNode.PreservedRouteParameters = new string[] { "productType", "category", "filter" };

一些路由值和保留的路由参数的组合对您的应用程序来说是有意义的。

有关这些选项的说明,请阅读如何使MvcSiteMapProvider记住用户的位置

键匹配

代码语言:javascript
复制
// This assumes you have explicitly set a key to "Home"
// in a node outside of the dynamic node provider.
dynamicNode.ParentKey = "Home";
dynamicNode.Key = "Product1";

// This node has the node declared above
// as its parent.
dynamicNode.ParentKey = "Product1";
dynamicNode.Key = "Product1Details";
票数 1
EN

Stack Overflow用户

发布于 2018-05-22 15:54:14

执行部分的解决方案。

非常感谢NightOwl888的详细回答,它帮助我解决了这个问题。我之前遵循了一个MSDN教程这里,我认为它使我对约束的使用感到困惑。

总之,我没有正确地定义约束,这导致了404和MVCSiteMapProvider的所有其他问题。这是一个工作解决方案的样本。

路由

代码语言:javascript
复制
routes.MapRoute(
         name: "Products",
         url: "{productType}/{category}/{filter}/{filterAction}/{filterId}",
         defaults: new { controller = "Products", action = "Index", productType = UrlParameter.Optional, category = UrlParameter.Optional, filter = UrlParameter.Optional, filterAction = UrlParameter.Optional, filterId = UrlParameter.Optional },
         constraints: new { productType = @"building-products|installation-materials|tools" },
        namespaces: new[] { "MyApp.Web.Controllers" }
        );

XML

代码语言:javascript
复制
<mvcSiteMapNode title="Product Type" dynamicNodeProvider="MyApp.Web.SiteMapProviders.ProductTypeSiteMapProvider, MyApp.Web">
  <mvcSiteMapNode title="Category" dynamicNodeProvider="MyApp.Web.SiteMapProviders.CategorySiteMapProvider, MyApp.Web">
    <mvcSiteMapNode title="Option" dynamicNodeProvider="MyApp.Web.SiteMapProviders.OptionSiteMapProvider, MyApp.Web" />
    <mvcSiteMapNode title="Association" dynamicNodeProvider="MyApp.Web.SiteMapProviders.AssociationSiteMapProvider, MyApp.Web" />
  </mvcSiteMapNode>
</mvcSiteMapNode>

4 DynamicNodes中的前2位给你一个想法

代码语言:javascript
复制
public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
    {
        using (var db = new ProductContext())
        {              
            foreach (var productType in db.ProductTypes.ToList())
            {
                DynamicNode dynamicNode = new DynamicNode();
                dynamicNode.Key = productType.Name.ToLower().Replace(" ", "-");
                dynamicNode.Title = productType.Name;
                dynamicNode.Clickable = false;
                yield return dynamicNode;
            }
        }
    }

public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
    {
        using (var db = new ProductContext())
        {              
            foreach (var category in db.Categories.ToList())
            {
                DynamicNode dynamicNode = new DynamicNode();
                dynamicNode.Key = category.Name.Replace(" ", "");
                dynamicNode.Title = category.Name;
                dynamicNode.Controller = "Products";
                dynamicNode.Action = "Index";
                dynamicNode.ParentKey = category.ProductType.Name.ToLower().Replace(" ", "-");
                dynamicNode.RouteValues.Add("productType", category.ProductType.Name.ToLower().Replace(" ", "-"));
                dynamicNode.RouteValues.Add("category", category.Name.ToLower().Replace(" ", "-"));
                dynamicNode.ImageUrl = category.CategoryImage();
                yield return dynamicNode;
            }
        }
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33159532

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档