0

我正在开发一个包含多个区域的 ASP.NET MVC 4 应用程序。根据项目要求,每个区域都应该有自己的站点地图文件。从这篇文章:https ://github.com/maartenba/MvcSiteMapProvider/wiki/Multiple-Sitemaps-in-One-Application ,我了解到为了使 MvcSiteMapProvider 与多个站点地图一起工作,必须使用外部 DI。因此,我安装了包:MvcSiteMapProvider.MVC4.DI.Unity.Modules 并根据本文修改了类 MvcSiteMapProviderContainerExtension。每当我尝试构建菜单时,都会显示以下错误:

声明了多个没有父键的节点。必须为 SiteMap 中除 1 个节点之外的所有节点设置父键。没有父键的节点将被视为根节点。请注意,在 XML 中定义节点时,XML 文件必须包含根节点。

您可以通过将 MvcSiteMapProvider_EnableSiteMapFile 设置设置为“false”来禁用 XML 配置。对于外部 DI 配置,您可以通过从 MvcSiteMapProvider DI 模块中删除 XmlSiteMapNodeProvider 来禁用 XML 解析。

或者,您可以将 MvcSiteMapProvider_IncludeRootNodeFromSiteMapFile 设置设置为“false”以从 XML 文件中排除根节点,但包括所有其他节点。对于外部 DI 配置,可以在 XmlSiteMapNodeProvider 的构造函数中找到此设置。

SiteMapCacheKey: 'sitemap://admin/'

不明确的根节点:

父键:'' | 控制器:“家”| 行动:“索引”| 区域:'' | 网址:'/' | 键:'rootarea' | 来源:'.sitemap XML 文件'

父键:'' | 控制器:'AdminHome' | 行动:“索引”| 区域:'管理员' | 网址:'/Admin/AdminHome' | 键:'adminarea' | 来源:'.sitemap XML 文件'

任何帮助将不胜感激。

如果您需要更多信息,请告诉我。

4

1 回答 1

2

Already answered at https://github.com/maartenba/MvcSiteMapProvider/issues/237. I am copying here for reference.

Here is an example of using 2 different SiteMap instances with Unity.

    public class MvcSiteMapProviderContainerExtension
            : UnityContainerExtension
    {
        protected override void Initialize()
        {
            bool securityTrimmingEnabled = false;
            bool enableLocalization = true;

            string rootSiteMapFile = HostingEnvironment.MapPath("~/Mvc.sitemap");
            string adminSiteMapFile = HostingEnvironment.MapPath("~/Areas/Admin/Mvc.sitemap");

            TimeSpan absoluteCacheExpiration = TimeSpan.FromMinutes(5);
            string[] includeAssembliesForScan = new string[] { "MccSiteMapProviderTest" };

            var currentAssembly = this.GetType().Assembly;
            var siteMapProviderAssembly = typeof(SiteMaps).Assembly;
            var allAssemblies = new Assembly[] { currentAssembly, siteMapProviderAssembly };
            var excludeTypes = new Type[] {
                typeof(SiteMapNodeVisibilityProviderStrategy),
                typeof(SiteMapXmlReservedAttributeNameProvider),
                typeof(SiteMapBuilderSetStrategy),
                typeof(SiteMapNodeUrlResolverStrategy),
                typeof(DynamicNodeProviderStrategy)
            };
            var multipleImplementationTypes = new Type[] {
                typeof(ISiteMapNodeUrlResolver),
                typeof(ISiteMapNodeVisibilityProvider),
                typeof(IDynamicNodeProvider)
            };

    // Single implementations of interface with matching name (minus the "I").
            CommonConventions.RegisterDefaultConventions(
                (interfaceType, implementationType) => this.Container.RegisterType(interfaceType, implementationType, new ContainerControlledLifetimeManager()),
                new Assembly[] { siteMapProviderAssembly },
                allAssemblies,
                excludeTypes,
                string.Empty);

    // Multiple implementations of strategy based extension points
            CommonConventions.RegisterAllImplementationsOfInterface(
                (interfaceType, implementationType) => this.Container.RegisterType(interfaceType, implementationType, implementationType.Name, new ContainerControlledLifetimeManager()),
                multipleImplementationTypes,
                allAssemblies,
                excludeTypes,
                "^Composite");

    // TODO: Find a better way to inject an array constructor

    // Url Resolvers
            this.Container.RegisterType<ISiteMapNodeUrlResolverStrategy, SiteMapNodeUrlResolverStrategy>(new InjectionConstructor(
                new ResolvedArrayParameter<ISiteMapNodeUrlResolver>(this.Container.ResolveAll<ISiteMapNodeUrlResolver>().ToArray())
                ));

    // Visibility Providers
            this.Container.RegisterType<ISiteMapNodeVisibilityProviderStrategy, SiteMapNodeVisibilityProviderStrategy>(new InjectionConstructor(
                new ResolvedArrayParameter<ISiteMapNodeVisibilityProvider>(this.Container.ResolveAll<ISiteMapNodeVisibilityProvider>().ToArray()),
                new InjectionParameter<string>(string.Empty)
                ));

    // Dynamic Node Providers
            this.Container.RegisterType<IDynamicNodeProviderStrategy, DynamicNodeProviderStrategy>(new InjectionConstructor(
                new ResolvedArrayParameter<IDynamicNodeProvider>(this.Container.ResolveAll<IDynamicNodeProvider>().ToArray())
                ));


    // Pass in the global controllerBuilder reference
            this.Container.RegisterInstance<ControllerBuilder>(ControllerBuilder.Current);
            this.Container.RegisterType<IControllerBuilder, ControllerBuilderAdaptor>(new PerResolveLifetimeManager());

            this.Container.RegisterType<IBuildManager, BuildManagerAdaptor>(new PerResolveLifetimeManager());

            this.Container.RegisterType<IControllerTypeResolverFactory, ControllerTypeResolverFactory>(new InjectionConstructor(
                new List<string>(),
                new ResolvedParameter<IControllerBuilder>(),
                new ResolvedParameter<IBuildManager>()));

    // Configure Security

    // IMPORTANT: Must give arrays of object a name in Unity in order for it to resolve them.
            this.Container.RegisterType<IAclModule, AuthorizeAttributeAclModule>("authorizeAttribute");
            this.Container.RegisterType<IAclModule, XmlRolesAclModule>("xmlRoles");
            this.Container.RegisterType<IAclModule, CompositeAclModule>(new InjectionConstructor(new ResolvedArrayParameter<IAclModule>(
                new ResolvedParameter<IAclModule>("authorizeAttribute"),
                new ResolvedParameter<IAclModule>("xmlRoles"))));



            this.Container.RegisterType<ISiteMapCacheKeyGenerator, SiteMapCacheKeyGenerator2>();


            this.Container.RegisterInstance<System.Runtime.Caching.ObjectCache>(System.Runtime.Caching.MemoryCache.Default);
            this.Container.RegisterType(typeof(ICacheProvider<>), typeof(RuntimeCacheProvider<>));

            this.Container.RegisterType<ICacheDependency, RuntimeFileCacheDependency>(
                "rootSiteMapCacheDependency", new InjectionConstructor(rootSiteMapFile));

            this.Container.RegisterType<ICacheDependency, RuntimeFileCacheDependency>(
                "adminSiteMapCacheDependency", new InjectionConstructor(adminSiteMapFile));

            this.Container.RegisterType<ICacheDetails, CacheDetails>("rootSiteMapCacheDetails",
                new InjectionConstructor(absoluteCacheExpiration, TimeSpan.MinValue, new ResolvedParameter<ICacheDependency>("rootSiteMapCacheDependency")));

            this.Container.RegisterType<ICacheDetails, CacheDetails>("adminSiteMapCacheDetails",
                new InjectionConstructor(absoluteCacheExpiration, TimeSpan.MinValue, new ResolvedParameter<ICacheDependency>("adminSiteMapCacheDependency")));

// Configure the visitors
            this.Container.RegisterType<ISiteMapNodeVisitor, UrlResolvingSiteMapNodeVisitor>();

// Prepare for the sitemap node providers
            this.Container.RegisterType<IXmlSource, FileXmlSource>("rootSiteMapXmlSource", new InjectionConstructor(rootSiteMapFile));
            this.Container.RegisterType<IXmlSource, FileXmlSource>("adminSiteMapXmlSource", new InjectionConstructor(adminSiteMapFile));

    // IMPORTANT: Must give arrays of object a name in Unity in order for it to resolve them.
    // Register the sitemap node providers
        this.Container.RegisterInstance<ISiteMapNodeProvider>("rootXmlSiteMapNodeProvider",
            this.Container.Resolve<XmlSiteMapNodeProviderFactory>().Create(this.Container.Resolve<IXmlSource>("rootSiteMapXmlSource")), new ContainerControlledLifetimeManager());

        this.Container.RegisterInstance<ISiteMapNodeProvider>("adminXmlSiteMapNodeProvider",
            this.Container.Resolve<XmlSiteMapNodeProviderFactory>().Create(this.Container.Resolve<IXmlSource>("adminSiteMapXmlSource")), new ContainerControlledLifetimeManager());

        this.Container.RegisterInstance<ISiteMapNodeProvider>("ReflectionSiteMapNodeProvider1",
            this.Container.Resolve<ReflectionSiteMapNodeProviderFactory>().Create(includeAssembliesForScan), new ContainerControlledLifetimeManager());

        this.Container.RegisterType<ISiteMapNodeProvider, CompositeSiteMapNodeProvider>("rootSiteMapNodeProvider", 
            new ContainerControlledLifetimeManager(),
            new InjectionConstructor(new ResolvedArrayParameter<ISiteMapNodeProvider>(
                new ResolvedParameter<ISiteMapNodeProvider>("rootXmlSiteMapNodeProvider"),
                new ResolvedParameter<ISiteMapNodeProvider>("ReflectionSiteMapNodeProvider1"))));

        this.Container.RegisterType<ISiteMapNodeProvider, CompositeSiteMapNodeProvider>("adminSiteMapNodeProvider",
            new ContainerControlledLifetimeManager(),
            new InjectionConstructor(new ResolvedArrayParameter<ISiteMapNodeProvider>(
                new ResolvedParameter<ISiteMapNodeProvider>("adminXmlSiteMapNodeProvider"),
                new ResolvedParameter<ISiteMapNodeProvider>("ReflectionSiteMapNodeProvider1"))));

    // Configure the builders
        this.Container.RegisterInstance<ISiteMapBuilder>("rootSiteMapBuilder", 
            this.Container.Resolve<SiteMapBuilderFactory>().Create(this.Container.Resolve<ISiteMapNodeProvider>("rootSiteMapNodeProvider")), 
            new ContainerControlledLifetimeManager());

        this.Container.RegisterInstance<ISiteMapBuilder>("adminSiteMapBuilder", 
            this.Container.Resolve<SiteMapBuilderFactory>().Create(this.Container.Resolve<ISiteMapNodeProvider>("adminSiteMapNodeProvider")), 
            new ContainerControlledLifetimeManager());      

    // Configure the builder sets
        this.Container.RegisterType<ISiteMapBuilderSet, SiteMapBuilderSet>("rootBuilderSet",
            new InjectionConstructor(
                "default",
                securityTrimmingEnabled,
                enableLocalization,
                new ResolvedParameter<ISiteMapBuilder>("rootSiteMapBuilder"),
                new ResolvedParameter<ICacheDetails>("rootSiteMapCacheDetails")));

        this.Container.RegisterType<ISiteMapBuilderSet, SiteMapBuilderSet>("adminBuilderSet",
            new InjectionConstructor(
                "admin",
                securityTrimmingEnabled,
                enableLocalization,
                new ResolvedParameter<ISiteMapBuilder>("adminSiteMapBuilder"),
                new ResolvedParameter<ICacheDetails>("adminSiteMapCacheDetails")));
        }
    }

Note that there are factories called SiteMapBuilderFactory, XmlSiteMapNodeProviderFactory, and ReflectionSiteMapNodeProviderFactory that are specific to Unity and other DI containers that don't allow you to insert individual objects without binding to the constructor signature that should be used in this case. This will help ensure minimal number of future changes as the constructor signature is likely to change over time.

于 2013-11-07T08:44:50.833 回答