看起来MVCSitemapProvider的IsCurrentNode属性区别于URL。
E.g。
https://localhost/MvcApplication1/customer/exportdata (no match)
https://localhost/MvcApplication1/Customer/ExportData (works)
由于URL的情况有点难以确定,有没有办法解决这个问题?
这就是我的网站地图目前的样子:
<mvcSiteMapNode title="Home" controller="Home" action="Index" clickable="false">
<mvcSiteMapNode title="Meine Aufträge" controller="Home" action="Index">
<mvcSiteMapNode title="Übersicht" controller="Customer/Orders" action="Index"/>
<mvcSiteMapNode title="Rechnungen" controller="Customer/Bills" action="Index" roles="CompanyAdmin"/>
<mvcSiteMapNode title="Export" controller="Customer/ExportData" action="Index"/>
</mvcSiteMapNode>
<mvcSiteMapNode title="Firmenadministration" controller="Home" action="Index">
<mvcSiteMapNode title="Übersicht" controller="AllOrders" action="About"/>
</mvcSiteMapNode>
<mvcSiteMapNode title="Freelancer" url="http://www.myblog1.com" >
<mvcSiteMapNode title="Übersicht" url="http://www.myblog2.com" />
<mvcSiteMapNode title="Rechnungen" url="http://www.myblog3.com" />
</mvcSiteMapNode>
</mvcSiteMapNode>
部分内容只是测试数据。
答案 0 :(得分:1)
只要您使用URL Helper构建您的网址,使用.NET 4.5即可轻松实施小写网址:
public static void RegisterRoutes(RouteCollection routes)
{
routes.LowercaseUrls = true;
...
}
此外,通常最佳做法是使用小写URL来获得更好的SEO和缓存支持。
我怀疑之前没有报告过,因为大多数人使用@Html.ActionLink
,@Html.RouteLink
或@Html.Url
帮助程序来构建他们的网址,这总是使他们的情况相同,所以比较将始终有效。
如果您将此报告为新问题@ GitHub,我会很感激,因此我们可以将其添加到工作队列中,因为我同意这是一个需要解决的错误。
潜在的问题有两个:
这意味着如果所有网址都是小写生成的,那么问题就会消失。这是因为MvcSiteMapProvider使用MVC UrlHelper类来生成URL。
然而,另一个可能的解决方法是重新排列比较完成的顺序,以便首先比较路线。您可以通过继承RequestCacheableSiteMap并重写FindSiteMapNode()来实现此目的。
// Original
protected virtual ISiteMapNode FindSiteMapNode(HttpContextBase httpContext)
{
// Match RawUrl
var node = this.FindSiteMapNodeFromRawUrl(httpContext);
// Try MVC
if (node == null)
{
node = this.FindSiteMapNodeFromMvc(httpContext);
}
// Try ASP.NET Classic (for interop)
if (node == null)
{
node = this.FindSiteMapNodeFromAspNetClassic(httpContext);
}
// Try the path without the querystring
if (node == null)
{
node = this.FindSiteMapNode(httpContext.Request.Path);
}
// Check accessibility
return this.ReturnNodeIfAccessible(node);
}
// Fixed
protected override ISiteMapNode FindSiteMapNode(HttpContextBase httpContext)
{
// Match MVC
var node = this.FindSiteMapNodeFromMvc(httpContext);
// Try RawUrl
if (node == null)
{
node = this.FindSiteMapNodeFromRawUrl(httpContext);
}
// Try ASP.NET Classic (for interop)
if (node == null)
{
node = this.FindSiteMapNodeFromAspNetClassic(httpContext);
}
// Try the path without the querystring
if (node == null)
{
node = this.FindSiteMapNode(httpContext.Request.Path);
}
// Check accessibility
return this.ReturnNodeIfAccessible(node);
}
然后,您可以继承SiteMapFactory或创建自己的ISiteMapFactory,返回您的SiteMap类型并将其注入外部DI。如果使用内部DI容器,此解决方案将无法使用。
using System;
using MvcSiteMapProvider.Builder;
using MvcSiteMapProvider.Web.Mvc;
using MvcSiteMapProvider.Web;
public class MySiteMapFactory
: ISiteMapFactory
{
public MySiteMapFactory(
ISiteMapPluginProviderFactory pluginProviderFactory,
IMvcResolverFactory mvcResolverFactory,
IMvcContextFactory mvcContextFactory,
ISiteMapChildStateFactory siteMapChildStateFactory,
IUrlPath urlPath,
IControllerTypeResolverFactory controllerTypeResolverFactory,
IActionMethodParameterResolverFactory actionMethodParameterResolverFactory
)
{
if (pluginProviderFactory == null)
throw new ArgumentNullException("pluginProviderFactory");
if (mvcResolverFactory == null)
throw new ArgumentNullException("mvcResolverFactory");
if (mvcContextFactory == null)
throw new ArgumentNullException("mvcContextFactory");
if (siteMapChildStateFactory == null)
throw new ArgumentNullException("siteMapChildStateFactory");
if (urlPath == null)
throw new ArgumentNullException("urlPath");
if (controllerTypeResolverFactory == null)
throw new ArgumentNullException("controllerTypeResolverFactory");
if (actionMethodParameterResolverFactory == null)
throw new ArgumentNullException("actionMethodParameterResolverFactory");
this.pluginProviderFactory = pluginProviderFactory;
this.mvcResolverFactory = mvcResolverFactory;
this.mvcContextFactory = mvcContextFactory;
this.siteMapChildStateFactory = siteMapChildStateFactory;
this.urlPath = urlPath;
this.controllerTypeResolverFactory = controllerTypeResolverFactory;
this.actionMethodParameterResolverFactory = actionMethodParameterResolverFactory;
}
protected readonly ISiteMapPluginProviderFactory pluginProviderFactory;
protected readonly IMvcResolverFactory mvcResolverFactory;
protected readonly IMvcContextFactory mvcContextFactory;
protected readonly ISiteMapChildStateFactory siteMapChildStateFactory;
protected readonly IUrlPath urlPath;
protected readonly IControllerTypeResolverFactory controllerTypeResolverFactory;
protected readonly IActionMethodParameterResolverFactory actionMethodParameterResolverFactory;
#region ISiteMapFactory Members
public virtual ISiteMap Create(ISiteMapBuilder siteMapBuilder, ISiteMapSettings siteMapSettings)
{
var routes = mvcContextFactory.GetRoutes();
var requestCache = mvcContextFactory.GetRequestCache();
// IMPORTANT: We need to ensure there is one instance of controllerTypeResolver and
// one instance of ActionMethodParameterResolver per SiteMap instance because each of
// these classes does internal caching.
var controllerTypeResolver = controllerTypeResolverFactory.Create(routes);
var actionMethodParameterResolver = actionMethodParameterResolverFactory.Create();
var mvcResolver = mvcResolverFactory.Create(controllerTypeResolver, actionMethodParameterResolver);
var pluginProvider = pluginProviderFactory.Create(siteMapBuilder, mvcResolver);
return new MySiteMap(
pluginProvider,
mvcContextFactory,
siteMapChildStateFactory,
urlPath,
siteMapSettings,
requestCache);
}
#endregion
}
然后在MvcSiteMapProvider DI模块中注入您的工厂(显示的StructureMap示例):
For<ISiteMapFactory>().Use<MySiteMapFactory>();
请注意,您必须重新实现RequestCacheableSiteMap的构造函数,以便将所有依赖项传递到对象中,就像它们在MySiteMapFactory实现中一样。
我没有测试过这个解决方案,以确定是否有任何副作用,特别是如果您使用混合的路由和URL。