如何使用带有Unity DI的MVCSiteMapProvider v4配置多个站点地图

时间:2013-10-15 17:43:30

标签: c# dependency-injection unity-container mvcsitemapprovider

我正在开发一个包含多个区域的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 /'

     

不明确的根节点:

     

ParentKey:''|控制器:'主页'|行动:'指数'|区域:''|网址:'/'|关键:'rootarea'|来源:'。sitemap XML File'

     

ParentKey:''|控制器:'AdminHome'|行动:'指数'|区域:'管理员'|网址:'/ Admin / AdminHome'|关键:'adminarea'|来源:'。sitemap XML File'

非常感谢任何帮助。

如果您需要进一步的信息,请告诉我。

1 个答案:

答案 0 :(得分:2)

已在https://github.com/maartenba/MvcSiteMapProvider/issues/237处回答。我在这里复制以供参考。

以下是使用Unity的2个不同SiteMap个实例的示例。

    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")));
        }
    }

请注意,有些工厂名为SiteMapBuilderFactoryXmlSiteMapNodeProviderFactoryReflectionSiteMapNodeProviderFactory,这些工厂特定于Unity和其他DI容器,不允许您插入单个对象而不绑定到在这种情况下应该使用的构造函数签名。这将有助于确保最小数量的未来更改,因为构造函数签名可能会随着时间的推移而发生变化。