我已经和MVC SiteMapProvider混了一段时间了,我很喜欢它。我正在建设一个电子商务网站,到目前为止,它在我的开发过程中运行得很好。
有一个问题我似乎无法解决,那就是如何让dynamicNode在第一级工作。
就像这样:
www.mysite.com/{type}/{category}/{filter}只有3种类型,所以现在我只有3个控制器以该类型命名,它们都使用相同的逻辑和viewModels,这并不是理想的可维护性设置。我的routeConfig包括三条这样的路线。
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。
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生成我的节点。只是在没有静态命名第一级的时候遇到了第一级的麻烦
masonry-products/ vs. {productType}/如果你有解决办法,请告诉我。希望NightOwl能加入进来。
发布于 2015-10-16 18:23:42
.NET的路由框架非常灵活。
对于这种情况,只需对类型使用约束即可。有两种方式:
如果您没有预料到大量的更改,那么第一个选项就不会那么糟糕了:
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" }
);第二种选择更具动态性:
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;
}
}缓存在这里是必要的,因为每个请求都会受到约束。
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属性中定义一个父键,以便从提供程序上附加顶级节点。
路由
dynamicNode.Controller = "Product";
dynamicNode.Action = "Index";
dynamicNode.RouteValues.Add("productType", "hardscape-products");
dynamicNode.RouteValues.Add("category", "some-category");
dynamicNode.RouteValues.Add("filter", "some-filter");或
dynamicNode.Controller = "Product";
dynamicNode.Action = "Index";
dynamicNode.PreservedRouteParameters = new string[] { "productType", "category", "filter" };或
一些路由值和保留的路由参数的组合对您的应用程序来说是有意义的。
有关这些选项的说明,请阅读如何使MvcSiteMapProvider记住用户的位置。
键匹配
// 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";发布于 2018-05-22 15:54:14
执行部分的解决方案。
非常感谢NightOwl888的详细回答,它帮助我解决了这个问题。我之前遵循了一个MSDN教程这里,我认为它使我对约束的使用感到困惑。
总之,我没有正确地定义约束,这导致了404和MVCSiteMapProvider的所有其他问题。这是一个工作解决方案的样本。
路由
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
<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位给你一个想法
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;
}
}
}https://stackoverflow.com/questions/33159532
复制相似问题