我正在尝试在我的ASP.Net MVC 5应用程序中使用MVCSiteMapProvider。可以找到大量资源和教程,但大多数都是基于XML的配置。
在我的应用程序中,属性路由已经被使用,我想使用带有属性的MvcSiteMapProvider但是这个混合没有足够的资源,我有一些问题。
例如我有三个动作如下:
//HomeController
[Route(@"~/home", Name = "CustomerHomeIndex")]
[MvcSiteMapNode(Title = "Home Page", Key = "Home")]
public ActionResult Index() {
return View()
}
//AccountController
[Route(@"~/account", Name = "AccountIndex")]
[MvcSiteMapNode(Title = "Accounts", ParentKey = "Home", Key = "AccountIndex")]
public ActionResult Index() {
// fetching records from database
return View();
}
[Route(@"~/account-management/{id:int}/{domain:regex(^([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$)}", Name = "AccountDetail")]
[MvcSiteMapNode(Title = "Account Detail", ParentKey = "AccountIndex", Key = "AccountDetail")]
public ActionResult Details(string domain, int id) {
// fetching record from database by parameters
return View();
}
我还在我的视图中添加了SiteMapPath代码
//Details.cshtml
@Html.MvcSiteMap().SiteMapPath()
但是没有任何结果显示出来。在我看来,这是关于preservedRouteParameters
,但我无法找到有关属性路由的MvcSiteMapNode
属性中使用的此参数的任何内容。
其实我还有另外一个关于本地化的问题,我想从资源文件中获取标题,一切都已存在于全局资源文件中。我读了一些关于本地化支持的内容,但它们也与基于XML的配置有关。
答案 0 :(得分:3)
默认情况下,启用XML和.NET属性的提供程序。在此配置中,必须将根节点(没有父键的节点)放在XML文件中。要在XML中没有任何配置的情况下独占使用.NET属性,您需要从配置中删除XML节点提供程序。
内部DI:
<appSettings>
<add key="MvcSiteMapProvider_EnableSiteMapFile" value="false"/>
</appSettings>
外部DI(显示的StructureMap示例):
// Register the sitemap node providers
var siteMapNodeProvider = this.For<ISiteMapNodeProvider>().Use<CompositeSiteMapNodeProvider>()
.EnumerableOf<ISiteMapNodeProvider>().Contains(x =>
{
//Remove the XmlSiteMapNodeProvider
//x.Type<XmlSiteMapNodeProvider>()
// .Ctor<bool>("includeRootNode").Is(true)
// .Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
// .Ctor<IXmlSource>().Is(xmlSource);
x.Type<ReflectionSiteMapNodeProvider>()
.Ctor<IEnumerable<string>>("includeAssemblies").Is(includeAssembliesForScan)
.Ctor<IEnumerable<string>>("excludeAssemblies").Is(new string[0]);
});
您还需要确保包含控制器的程序集包含在IncludeAssembliesForScan配置设置中。请注意,NuGet包自动包含您安装MvcSiteMapProvider的程序集,因此如果您的控制器都在您的主MVC项目中,则不需要触摸它。
内部DI:
<appSettings>
<add key="MvcSiteMapProvider_IncludeAssembliesForScan" value="MyAssembly,MyOtherAssembly"/>
</appSettings>
外部DI:
string[] includeAssembliesForScan = new string[] { "MyAssembly", "MyOtherAssembly" };
... Other code omitted ...
// Register the sitemap node providers
var siteMapNodeProvider = this.For<ISiteMapNodeProvider>().Use<CompositeSiteMapNodeProvider>()
.EnumerableOf<ISiteMapNodeProvider>().Contains(x =>
{
//Remove the XmlSiteMapNodeProvider
//x.Type<XmlSiteMapNodeProvider>()
// .Ctor<bool>("includeRootNode").Is(true)
// .Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
// .Ctor<IXmlSource>().Is(xmlSource);
x.Type<ReflectionSiteMapNodeProvider>()
.Ctor<IEnumerable<string>>("includeAssemblies").Is(includeAssembliesForScan) // <- Setting is injected here
.Ctor<IEnumerable<string>>("excludeAssemblies").Is(new string[0]);
});
要使它与AttributeRouting一起使用没有什么特别之处 - MvcSiteMapProvider会自动选择这些路由,只要你正确配置它们并在MVC中工作就可以正常工作。
是的,您可能需要将PreservedRouteParameters用于包含自定义参数的操作,例如。
[Route(@"~/account-management/{id:int}/{domain:regex(^([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$)}", Name = "AccountDetail")]
[MvcSiteMapNode(Title = "Account Detail", ParentKey = "AccountIndex", Key = "AccountDetail", PreservedRouteParameters="domain,id")]
public ActionResult Details(string domain, int id) {
// fetching record from database by parameters
return View();
}
在您的简单示例中,这将正常工作。但是,在将节点级别嵌套到第一个节点之外时,您需要完全了解savedRouteParameters如何正确使用它们。您不能使用具有相同键名的参数,这些参数具有在同一请求中可见的不同含义,因为MvcSiteMapProvider始终将当前请求中的值插入到具有匹配键名的所有节点中。您还必须在(子节点的)请求中提供祖先节点所需的任何密钥,以便导航工作。有关完整详细信息,请参阅How to Make MvcSiteMapProvider Remember a User's Position和演示代码。
请参阅reading localization from an external assembly。但请注意,从v4.6.15开始,唯一可行的方法是使用外部DI容器注入自定义IStringLocalizer。
默认本地化实现只能支持放入App_GlobalResources文件夹的文件。请注意,这是problematic with MVC,因为添加这些文件时的默认设置会使它们以无法从MVC访问的方式进行编译。我们目前gathering requirements to make a new extension point允许从备用位置配置资源。