我正在使用 MVC4,MvcSiteMapProvider v3.2.1(需要升级到v4)。
我的问题是应用程序是巨大的。我想模块化应用程序并使模块可插入。
由于站点地图已经非常庞大,我想让站点地图也成为pluggalbe。
有没有办法在应用程序启动时使用根站点地图从多个xml文件加载节点来构建站点地图?
以下是解释的例子:
原始站点地图:
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0"
xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-3.0 MvcSiteMapSchema.xsd"
enableLocalization="true">
<mvcSiteMapNode title="Home" controller="Home" action="Index">
<mvcSiteMapNode title="Staff List" controller="Staff" action="List">
<mvcSiteMapNode title="Create Staff" controller="Staff" action="Create"/>
<mvcSiteMapNode title="Edit Staff" controller="Staff" action="Edit"/>
<mvcSiteMapNode title="View Staff" controller="Staff" action="Details">
<mvcSiteMapNode >
...
</mvcSiteMapNode>
</mvcSiteMapNode>
<mvcSiteMapNode title="Client List" controller="Client" action="List">
<mvcSiteMapNode title="Create Client" controller="Client" action="Create"/>
<mvcSiteMapNode title="Edit Client" controller="Client" action="Edit"/>
<mvcSiteMapNode title="View Client" controller="Client" action="Details">
<mvcSiteMapNode >
...
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMap>
我想将站点地图拆分为:
根站点地图:
<mvcSiteMapNode title="Home" controller="Home" action="Index">
<subsitemap file="StaffSiteMap">// something like this.
<subsitemap file="ClientSiteMap">// something like this.
</mvcSiteMapNode>
</mvcSiteMap>
StaffSiteMap:
<mvcSiteMapNode title="Staff List" controller="Staff" action="List">
<mvcSiteMapNode title="Create Staff" controller="Staff" action="Create"/>
<mvcSiteMapNode title="Edit Staff" controller="Staff" action="Edit"/>
<mvcSiteMapNode title="View Staff" controller="Staff" action="Details">
<mvcSiteMapNode />
...
</mvcSiteMapNode>
</mvcSiteMapNode>
ClientSiteMap:
<mvcSiteMapNode title="Client List" controller="Client" action="List">
<mvcSiteMapNode title="Create Client" controller="Client" action="Create"/>
<mvcSiteMapNode title="Edit Client" controller="Client" action="Edit"/>
<mvcSiteMapNode title="View Client" controller="Client" action="Details">
<mvcSiteMapNode >
...
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMapNode>
答案 0 :(得分:1)
您的方法可能会导致您创建比您需要的节点更多的节点。除非在搜索引擎中索引您的CRUD操作很重要,否则有一个快捷方式。您可以将一组节点用于&#34;索引&#34;,&#34;创建&#34;,&#34;编辑&#34;,&#34;删除&#34;,&#34;详情& #34;并使用preservedRouteParameters
强制他们匹配所有可能的&#34; id&#34;。
首先,您需要正确嵌套节点,以便在每种情况下都显示正确的痕迹痕迹。
<mvcSiteMapNode title="Staff" controller="Staff" action="List">
<mvcSiteMapNode title="Create New" action="Create" />
<mvcSiteMapNode title="Details" action="Details" preservedRouteParameters="id">
<mvcSiteMapNode title="Edit" action="Edit" preservedRouteParameters="id"/>
<mvcSiteMapNode title="Delete" action="Delete" preservedRouteParameters="id"/>
</mvcSiteMapNode>
</mvcSiteMapNode>
&#34;编辑&#34;,&#34;删除&#34;和&#34;详细信息&#34;节点将位于菜单或其他控件中,因此在这种情况下,您需要使用FilteredSiteMapNodeVisibilityProvider
使它们不可见。您可以在配置中将默认可见性提供程序设置为FilteredSiteMapNodeVisibilityProvider
,这样您就不必在每个节点上设置它。您还应将VisibilityAffectsDescendants
属性设置为false,以确保每个节点始终打开和关闭,而不是在其父节点不可见时不可见。
内部DI(web.config):
<appSettings>
<add key="MvcSiteMapProvider_DefaultSiteMapNodeVisibiltyProvider" value="MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider"/>
<add key="MvcSiteMapProvider_VisibilityAffectsDescendants" value="false"/>
</appSettings>
外部DI(在DI模块中,显示StructureMap示例):
bool visibilityAffectsDescendants = false;
// Module code omitted here...
// Visibility Providers
this.For<ISiteMapNodeVisibilityProviderStrategy>().Use<SiteMapNodeVisibilityProviderStrategy>()
.Ctor<string>("defaultProviderName").Is("MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider");
要完成可见性,您需要设置每个节点的visibility
属性。
<mvcSiteMapNode title="Staff" controller="Staff" action="List">
<mvcSiteMapNode title="Create New" action="Create" visibility="SiteMapPathHelper,!*" />
<mvcSiteMapNode title="Details" action="Details" preservedRouteParameters="id" visibility="SiteMapPathHelper,!*">
<mvcSiteMapNode title="Edit" action="Edit" preservedRouteParameters="id" visibility="SiteMapPathHelper,!*"/>
<mvcSiteMapNode title="Delete" action="Delete" preservedRouteParameters="id" visibility="SiteMapPathHelper,!*"/>
</mvcSiteMapNode>
</mvcSiteMapNode>
此外,您可能希望设置&#34;索引&#34;的标题。节点因此它将显示当前记录的标题。您可以使用每种操作方法中的SiteMapTitleAttribute
执行此操作。
[SiteMapTitle("Name")]
public ActionResult Details(int id)
{
using (var db = new EntityContext())
{
var model = (from staff in db.Staff
where staff.Id == id
select staff).FirstOrDefault();
return View(model);
}
}
这假定有一个名为&#34;名称&#34;的字段。在你的员工表中。您还需要在编辑和删除方法(get和post)中设置它。但您还需要确保将属性目标设置为ParentNode
,以便它将覆盖&#34;详细信息&#34;的标题。节点
[SiteMapTitle("Name", Target = AttributeTarget.ParentNode)]
public ActionResult Edit(int id)
{
using (var db = new EntityContext())
{
var model = (from staff in db.Staff
where staff.Id == id
select staff).FirstOrDefault();
return View(model);
}
}
[HttpPost]
[SiteMapTitle("Name", Target = AttributeTarget.ParentNode)]
public ActionResult Edit(int id, Staff staff)
{
try
{
using (var db = new EntityContext())
{
var model = (from s in db.Staff
where s.Id == id
select s).FirstOrDefault();
if (model != null)
{
model.Name = staff.Name;
db.SaveChanges();
}
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
结果是你会有伪造的面包屑,根据选择的记录而改变。
Home > Staff
Home > Staff > Create New
Home > Staff > John Doe
Home > Staff > John Doe > Edit
Home > Staff > John Doe > Delete
有关可下载的工作演示,请参阅How to Make MvcSiteMapProvider Remember a User's Position代码下载中的Forcing-A-Match
项目。
请注意,也可以在MvcSiteMapProvider 3.x版中执行此操作,您只需在siteMap/providers/add
标记中设置默认可见性提供程序,并忽略有关VisibilityAffectsDescendants
的部分。
<siteMap defaultProvider="MvcSiteMapProvider" enabled="true">
<providers>
<clear/>
<add name="MvcSiteMapProvider"
type="MvcSiteMapProvider.DefaultSiteMapProvider, MvcSiteMapProvider"
siteMapFile="~/Mvc.Sitemap"
securityTrimmingEnabled="true"
cacheDuration="5"
enableLocalization="true"
scanAssembliesForSiteMapNodes="true"
excludeAssembliesForScan=""
includeAssembliesForScan=""
attributesToIgnore="bling,visibility"
nodeKeyGenerator="MvcSiteMapProvider.DefaultNodeKeyGenerator, MvcSiteMapProvider"
controllerTypeResolver="MvcSiteMapProvider.DefaultControllerTypeResolver, MvcSiteMapProvider"
actionMethodParameterResolver="MvcSiteMapProvider.DefaultActionMethodParameterResolver, MvcSiteMapProvider"
aclModule="MvcSiteMapProvider.DefaultAclModule, MvcSiteMapProvider"
routeMethod=""
siteMapNodeUrlResolver="MvcSiteMapProvider.DefaultSiteMapNodeUrlResolver, MvcSiteMapProvider"
siteMapNodeVisibilityProvider="MvcSiteMapProvider.FilteredSiteMapNodeVisibilityProvider, MvcSiteMapProvider"
siteMapProviderEventHandler="MvcSiteMapProvider.DefaultSiteMapProviderEventHandler, MvcSiteMapProvider"/>
</providers>
</siteMap>
如果您仍然认为有必要将SiteMap组织成较小的文件,则在版本3.x中无法实现。如果使用外部DI并且在同一个SiteMap中多次重复XmlSiteMapNodeProvider
,则版本4.x中可能会在配置中使用多个XML文件。以下是使用StructureMap的方法。
// Prepare for our node providers
var rootXmlSource = this.For<IXmlSource>().Use<FileXmlSource>()
.Ctor<string>("fileName").Is(HostingEnvironment.MapPath("~/Root.sitemap"));
var staffXmlSource = this.For<IXmlSource>().Use<FileXmlSource>()
.Ctor<string>("fileName").Is(HostingEnvironment.MapPath("~/Staff.sitemap"));
var clientXmlSource = this.For<IXmlSource>().Use<FileXmlSource>()
.Ctor<string>("fileName").Is(HostingEnvironment.MapPath("~/Client.sitemap"));
// Register the sitemap node providers
var siteMapNodeProvider = this.For<ISiteMapNodeProvider>().Use<CompositeSiteMapNodeProvider>()
.EnumerableOf<ISiteMapNodeProvider>().Contains(x =>
{
x.Type<XmlSiteMapNodeProvider>()
.Ctor<bool>("includeRootNode").Is(true)
.Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
.Ctor<IXmlSource>().Is(rootXmlSource);
x.Type<XmlSiteMapNodeProvider>()
.Ctor<bool>("includeRootNode").Is(false)
.Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
.Ctor<IXmlSource>().Is(staffXmlSource);
x.Type<XmlSiteMapNodeProvider>()
.Ctor<bool>("includeRootNode").Is(false)
.Ctor<bool>("useNestedDynamicNodeRecursion").Is(false)
.Ctor<IXmlSource>().Is(clientXmlSource);
x.Type<ReflectionSiteMapNodeProvider>()
.Ctor<IEnumerable<string>>("includeAssemblies").Is(includeAssembliesForScan)
.Ctor<IEnumerable<string>>("excludeAssemblies").Is(new string[0]);
});
请注意,每个XML文件仍然需要一个根节点,但如果includeRootNode参数为false,则不会将其解析为SiteMap。实际上,这与在Staff.sitemap
主页下面嵌套Client.sitemap
和Root.sitemap
文件的节点相同。
<强> Root.sitemap 强>
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0"
xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd">
<mvcSiteMapNode title="Home" controller="Home" action="Index" key="Home"/>
</mvcSiteMap>
<强> Staff.sitemap 强>
<?xml version="1.0" encoding="utf-8" ?>
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0"
xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd">
<mvcSiteMapNode title="Home" controller="Home" action="Index" key="Home">
<mvcSiteMapNode title="Staff List" controller="Staff" action="List">
<mvcSiteMapNode title="Create Staff" controller="Staff" action="Create"/>
<mvcSiteMapNode title="Edit Staff" controller="Staff" action="Edit"/>
<mvcSiteMapNode title="View Staff" controller="Staff" action="Details">
<mvcSiteMapNode >
...
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMapNode>
</mvcSiteMap>
请注意,您需要确保根节点在每个XML文件中都具有相同的密钥 - 最好的方法是将密钥明确设置为每个文件中的相同值。另请注意,使用XML时,无法将节点附加到比主页节点更深的不同文件中。虽然您可以在额外文件中将节点嵌套在彼此内,但它们都必须附加到主页。
但是,如果您使用IDynamicNodeProvider
,ISiteMapNodeProvider
或[MvcSiteMapNode]
attribute,则可以将每个提供商的节点嵌套在您需要的任何位置。