如何实现自定义SiteMapNodeProvider [英] How to implement custom SiteMapNodeProvider

查看:405
本文介绍了如何实现自定义SiteMapNodeProvider的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图适应MvcSiteMapProvider基于存储在数据库中的一些信息来创建面包屑。

在<一个答案href=\"http://stackoverflow.com/questions/19091576/mvcsitemapprovider-isitemapbuilder-in-conjunction-with-idynamicnodeprovider\">this后听起来倒是鼓舞,所以我实现我自己的SiteMapNodeProvider。但后来我不知道如何把事情了,因此新实施的SiteMapNodeProvider被用来代替静态xml文件(Mvc.sitemap)。的

由于我在我的项目中使用SimpleInjector,我在已经存在的注塑初始化code称为设置方法。

 公共静态无效初始化()
    {
        Injection.Global =新的Container();
        InitializeContainer(Injection.Global);
        Injection.Global.RegisterMvcControllers(Assembly.GetExecutingAssembly());
        Injection.Global.RegisterMvcAttributeFilterProvider();
        Injection.Global.Verify();
        DependencyResolver.SetResolver(新SimpleInjectorDependencyResolver(Injection.Global));
    }    私有静态无效InitializeContainer(集装箱货柜)
    {
        // DI的设置配置
        MvcSiteMapProviderContainerInitializer.SetUp(容器);        // ...注册一些其他的东西在这里我的项目...
    }

该MvcSiteMapProviderContainerInitializer类得到了由包创建的:'Mvcsitemapprovider.mvc4.di.simpleinjector / 4.4.5

有谁知道怎样做才能让我的项目中使用新创建的SiteMapNodeProvider?
我无法找到这个任何文件在正式实况...

编辑:我想你的建议(甚至删除旧的DI东西,只用从的NuGet包一个),但仍然我得到错误...
以下是我在我的MvcSiteMapProviderContainerInitializer

 公共静态无效的设置(集装箱货柜)
        {
            布尔securityTrimmingEnabled = FALSE;
            布尔enableLocalization = TRUE;
            串absoluteFileName = HostingEnvironment.MapPath(〜/ Mvc.sitemap);
            时间跨度absoluteCacheExpiration = TimeSpan.FromMinutes(5);
            字符串[] = includeAssembliesForScan新的字符串[] {testsitemap};//扩展到允许GetAllInstances阵列的分辨率(本机基于IEnumerable的)。
//源来自:HTTPS://simpleinjector.$c$cplex.com/wikipage标题= CollectionRegistrationExtensions
            AllowToResolveArraysAndLists(容器);            VAR currentAssembly = typeof运算(MvcSiteMapProviderContainerInitializer).Assembly;
            VAR siteMapProviderAssembly = typeof运算(地图).Assembly;
            VAR allAssemblies =新议会[] {currentAssembly,siteMapProviderAssembly};
            VAR excludeTypes =新类型[]
                {
                    typeof运算(SiteMapNodeVisibilityProviderStrategy)
                    typeof运算(SiteMapXmlReservedAttributeNameProvider)
                    typeof运算(SiteMapBuilderSetStrategy)
                    typeof运算(ControllerTypeResolverFactory)//由Eric-B增加了2013年6月28日,以避免违约单登记:
                    typeof运算(XmlSiteMapController)//由Eric-B为SimpleInjector.Verify方法添加2013年6月28日:
                    typeof运算(preservedRouteParameterCollection)
                    typeof运算(MvcResolver)
                    typeof运算(MvcSiteMapProvider.SiteMap)
                    typeof运算(MetaRobotsValueCollection)
                    typeof运算(RoleCollection)
                    typeof运算(SiteMapPluginProvider)
                    typeof运算(ControllerTypeResolver)
                    typeof运算(RouteValueDictionary)
                    typeof运算(AttributeDictionary)                    的typeof(SiteMapNodeCreator)
                };
            VAR multipleImplementationTypes =新类型[]
                {
                    typeof运算(ISiteMapNodeUrlResolver)
                    typeof运算(ISiteMapNodeVisibilityProvider)
                    typeof运算(IDynamicNodeProvider)
                };//相匹配的名称(去掉I)接口的单一实现。
            CommonConventions.RegisterDefaultConventions(
                (interfaceType,implementationType)= GT; container.RegisterSingle(interfaceType,implementationType)
                新议会[] {} siteMapProviderAssembly,
                allAssemblies,
                excludeTypes,
                的String.Empty);基于策略的扩展点//多个实现
            CommonConventions.RegisterAllImplementationsOfInterfaceSingle(
                (interfaceType,implementationTypes)= GT; container.RegisterAll(interfaceType,implementationTypes)
                multipleImplementationTypes,
                allAssemblies,
                新类型[0]
                ^复合);            container.Register&LT; XmlSiteMapController&GT;();//能见度提供商
            container.RegisterSingle&所述; ISiteMapNodeVisibilityProviderStrategy&GT;(()=&GT;
                                                                       新SiteMapNodeVisibilityProviderStrategy(
                                                                           container.GetAllInstances
                                                                               &LT; ISiteMapNodeVisibilityProvider&GT;()。
                                                                               ToArray的(),的String.Empty));//把全球ControllerBuilder类参考
            container.RegisterSingle&所述; ControllerBuilder类&GT;(()=&GT; ControllerBuilder.Current);            container.RegisterSingle&LT; IControllerBuilder,ControllerBuilderAdaptor&GT;();            container.RegisterSingle&LT; IBuildManager,BuildManagerAdaptor&GT;();            container.RegisterSingle&所述; IControllerTypeResolverFactory&GT;(()=&GT;
                                                               新ControllerTypeResolverFactory(新的字符串[0]
                                                                                                 container.GetInstance
                                                                                                     &LT; IControllerBuilder
                                                                                                     &GT;()
                                                                                                 container.GetInstance
                                                                                                     &所述; IBuildManager&GT;()));//配置安全
            container.RegisterAll&LT; IAclModule&GT;(typeof运算(AuthorizeAttributeAclModule)的typeof(XmlRolesAclModule));
            container.RegisterSingle&LT; IAclModule&GT;(()=&gt;新建CompositeAclModule(container.GetAllInstances&LT; IAclModule&GT;()ToArray的()));//设置缓存
            container.RegisterSingle&所述; System.Runtime.Caching.ObjectCache&GT;(()=&GT; System.Runtime.Caching.MemoryCache.Default);
            container.RegisterSingleOpenGeneric(typeof运算(ICacheProvider&LT;&GT;)的typeof(RuntimeCacheProvider&LT;&GT;));
            container.RegisterSingle&LT;&ICacheDependency的GT;(()=&gt;新建RuntimeFileCacheDependency(absoluteFileName));            container.RegisterSingle&LT; ICacheDetails&GT;(()=&gt;新建CacheDetails(absoluteCacheExpiration,TimeSpan.MinValue,container.GetInstance&LT;&ICacheDependency的GT;()));//配置访客
            container.RegisterSingle&LT; ISiteMapNodeVisitor,UrlResolvingSiteMapNodeVisitor&GT;();
// prepare的网站地图节点的供应商
            container.RegisterSingle&LT; ISiteMapXmlReservedAttributeNameProvider&GT;(
                ()=&GT;新SiteMapXmlReservedAttributeNameProvider(新的字符串[0]));            container.RegisterSingle&LT; IXmlSource&GT;(()=&gt;新建FileXmlSource(absoluteFileName));
            //注册网站地图节点商
            container.RegisterSingle&LT; XmlSiteMapNodeProvider&GT;(()=&GT; container.GetInstance&LT; XmlSiteMapNodeProviderFactory&GT;()
                .Create(container.GetInstance&所述; IXmlSource&GT;()));
            container.RegisterSingle&LT; ReflectionSiteMapNodeProvider&GT;(()=&GT; container.GetInstance&LT; ReflectionSiteMapNodeProviderFactory&GT;()
                .Create(includeAssembliesForScan));            //注册自定义站点地图结点提供
            container.RegisterSingle&LT; ISiteMapNodeProvider,CustomSiteMapNodeProvider&GT;();            //注册站点地图结点提供者(包括自定义的)的集合
            container.RegisterSingle&LT; ISiteMapBuilder&GT;(()=&GT; container.GetInstance&LT; SiteMapBuilderFactory&GT;()
                .Create(新CompositeSiteMapNodeProvider(
                    container.GetInstance&LT; XmlSiteMapNodeProvider&GT;()
                    container.GetInstance&LT; ReflectionSiteMapNodeProvider&GT;()
                    container.GetInstance&所述; CustomSiteMapNodeProvider&GT;())));
            container.RegisterAll&所述; ISiteMapBuilderSet&GT;(ResolveISiteMapBuilderSets(容器,securityTrimmingEnabled,enableLocalization));
            container.RegisterSingle&LT; ISiteMapBuilderSetStrategy&GT;(()=&gt;新建SiteMapBuilderSetStrategy(container.GetAllInstances&LT; ISiteMapBuilderSet方式&gt;()ToArray的()));
        }        私有静态的IEnumerable&LT; ISiteMapBuilderSet&GT; ResolveISiteMapBuilderSets(集装箱货柜,布尔securityTrimmingEnabled,布尔enableLocalization)
        {
            产量返回新SiteMapBuilderSet(
                默认,
                securityTrimmingEnabled,
                enableLocalization,
                container.GetInstance&LT; ISiteMapBuilder&GT;()
                container.GetInstance&所述; ICacheDetails&GT;());
        }        私有静态无效AllowToResolveArraysAndLists(集装箱货柜)
        {
            container.ResolveUnregisteredType + =(发件人,E)=&GT;
            {
                VAR的serviceType = e.UnregisteredServiceType;                如果(serviceType.IsArray)
                {
                    RegisterArrayResolver(E,集装箱,
                        serviceType.GetElementType());
                }
                否则,如果(serviceType.IsGenericType&安培;&安培;
                    serviceType.GetGenericTypeDefinition()== typeof运算(IList的&LT;&GT;))
                {
                    RegisterArrayResolver(E,集装箱,
                        serviceType.GetGenericArguments()[0]);
                }
            };
        }        私有静态无效RegisterArrayResolver(UnregisteredTypeEventArgs E,集装箱货柜,类型元素类型)
        {
            VAR制片= container.GetRegistration(typeof运算(IEnumerable的&LT;&GT;)
                .MakeGenericType(的ElementType));
            VAR enumerableEx pression = producer.BuildEx pression();
            VAR arrayMethod = typeof运算(可枚举).GetMethod(ToArray的)
                .MakeGenericMethod(元素类型);
            VAR arrayEx pression =前pression.Call(arrayMethod,enumerableEx pression);
            e.Register(arrayEx pression);
        }
    }

但我仍得到以下异常:


  

类型DynamicSiteMapNodeBuilder无需注册,可以发现
  隐式登记不能进行。的构造函数
  类型DynamicSiteMapNodeBuilder包含类型的参数
  ISiteMapNodeCreator名为'siteMapNodeCreator',是不是
  注册。请确保ISiteMapNodeCreator在注册
  容器,或更改DynamicSiteMapNodeBuilder的构造函数。



解决方案

首先,与现有DI设置集成,你应该安装 MvcSiteMapProvider.MVC4.DI.SimpleInjector.Modules 来代替 MvcSiteMapProvider.MVC4.DI.SimpleInjector 。您可以通过运行从包管理器控制台命令降级:

PM>卸载封装-Id MvcSiteMapProvider.MVC4.DI.SimpleInjector

一定不要卸载任何依赖关系。这将确保你没有2台DI初始化code在您的项目 - 应该只有1对整个应用程序

接下来,你需要接线为DI以及由MvcSiteMapProvider需要一些其他初始化code。在<一个href=\"https://github.com/maartenba/MvcSiteMapProvider/tree/master/src/MvcSiteMapProvider/$c$cAsConfiguration/SimpleInjector/DI/SimpleInjector\"相对=nofollow>自述文件包含说明如何做到这一点。这里是你将如何与现有的配置做到这一点。

 公共静态无效初始化()
{
    Injection.Global =新的Container();
    InitializeContainer(Injection.Global);
    Injection.Global.RegisterMvcControllers(Assembly.GetExecutingAssembly());
    Injection.Global.RegisterMvcAttributeFilterProvider();
    Injection.Global.Verify();
    DependencyResolver.SetResolver(新SimpleInjectorDependencyResolver(Injection.Global));
}私有静态无效InitializeContainer(集装箱货柜)
{
    // DI的设置配置(要求)
    MvcSiteMapProviderContainerInitializer.SetUp(容器);    //设置全球地图装载器(必填)
    MvcSiteMapProvider.SiteMaps.Loader = container.GetInstance&LT; ISiteMapLoader&GT;();    //检查所有配置.sitemap文件,以确保它们遵循XSD的MvcSiteMapProvider(可选)
    VAR验证= container.GetInstance&LT; ISiteMapXmlValidator&GT;();
    validator.ValidateXml(HostingEnvironment.MapPath(〜/ Mvc.sitemap));    //注册搜索引擎站点地图路径(可选)
    XmlSiteMapController.RegisterRoutes(RouteTable.Routes); //注意:您可以把它放在你的RouteConfig.cs如果所需的文件。    // ...注册一些其他的东西,为您的网站项目...
}

如果在 /sitemap.xml 端点不工作,你可能还需要添加此行注册XmlSiteMapController:

  Injection.Global.RegisterMvcControllers(typeof运算(MvcSiteMapProvider.SiteMaps).Assembly);

要实现ISiteMapNodeProvider,这里有个例子:<一href=\"http://stackoverflow.com/questions/19091576/mvcsitemapprovider-isitemapbuilder-in-conjunction-with-idynamicnodeprovider/19120660#19120660\">MvcSiteMapProvider ISiteMapBuilder与IDynamicNodeProvider 结合。

要注册您的自定义ISiteMapNodeProvider,你只需要确保它被添加到Si​​teMapBuilder的构造函数。您还可以排除下面根据您的需求从code现有SiteMapNodeProviders。

  //注册网站地图节点商
container.RegisterSingle&LT; XmlSiteMapNodeProvider&GT;(()=&GT; container.GetInstance&LT; XmlSiteMapNodeProviderFactory&GT;()
    .Create(container.GetInstance&所述; IXmlSource&GT;()));
container.RegisterSingle&LT; ReflectionSiteMapNodeProvider&GT;(()=&GT; container.GetInstance&LT; ReflectionSiteMapNodeProviderFactory&GT;()
    .Create(includeAssembliesForScan));//注册自定义站点地图结点提供
container.RegisterSingle&LT; ISiteMapNodeProvider,CustomSiteMapNodeProvider&GT;();//注册站点地图结点提供者(包括自定义的)的集合
container.RegisterSingle&LT; ISiteMapBuilder&GT;(()=&GT; container.GetInstance&LT; SiteMapBuilderFactory&GT;()
    .Create(新CompositeSiteMapNodeProvider(
        container.GetInstance&LT; XmlSiteMapNodeProvider&GT;()
        container.GetInstance&LT; ReflectionSiteMapNodeProvider&GT;()
        container.GetInstance&所述; CustomSiteMapNodeProvider&GT;())));

请注意,IDynamicNodeProvider(这是记录)做几乎完全一样的东西作为ISiteMapNodeProvider,所以你可以使用该选项。有3个主要的差异:


  1. 随着IDynamicNodeProvider,你必须创建一个模板节点定义dynamicNodeProvider属性,本身不会包括在网站地图模板节点,所以它必须结合与处理动态节点ISiteMapNodeProvider实现使用(内置ISiteMapNodeProviders自动执行此操作)。

  2. IDynamicNodeProvider不会,因为它已经被双方XmlSiteMapNodeProvider和ReflectionSiteMapNodeProvider处理需要是DI设置的一部分。

  3. 随着ISiteMapNodeProvider,您直接与ISiteMapNode对象的工作,具有IDynamicNodeProvider您正在使用一个抽象(DynamicNodeProvider)工作,有是自动发生转换。

关于SimpleInjector.Verify

如果你想验证()工作,你需要添加以下的MvcSiteMapProviderContainerInitializer的excludeTypes阵列。

  typeof运算(SiteMapNodeCreator)
typeof运算(DynamicSiteMapNodeBuilder)

我已经将它们添加到模块,将在包的NuGet的下一个版本,但这些模块不更新,所以你必须手工完成。

注意,验证()方法试图创建与容器注册的所有实例 - 包括那些永远不会由容器在现实世界中创建的对象。因此,如果您使用验证你必须要更加勤奋的东西是不是无意中注册()方法。这使得基于约定登记更难做。

I am trying to adapt the MvcSiteMapProvider to create the breadcrumb based on some Information stored in a database.

The answer in this post sounded promising so i implemented my own SiteMapNodeProvider. But then i didnt know how to wire things up so the newly implemented SiteMapNodeProvider is used instead of the static xml file ("Mvc.sitemap").

As i am using SimpleInjector in my project, i called the setup method in my already existent Injection-initialization code.

 public static void Initialize()
    {
        Injection.Global = new Container();
        InitializeContainer(Injection.Global);
        Injection.Global.RegisterMvcControllers(Assembly.GetExecutingAssembly());
        Injection.Global.RegisterMvcAttributeFilterProvider();
        Injection.Global.Verify();
        DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(Injection.Global));
    }

    private static void InitializeContainer(Container container)
    {
        // Setup configuration of DI
        MvcSiteMapProviderContainerInitializer.SetUp(container);

        //... register some other stuff for my project here ...
    }

The MvcSiteMapProviderContainerInitializer class got created by the package: 'Mvcsitemapprovider.mvc4.di.simpleinjector/4.4.5'

Does anybody know what to do to make my project use the newly created SiteMapNodeProvider? I couldnt find any documentation about this in the official docu...

edit: i tried what you suggested (even removed the old DI stuff and only used the one from the nuget-package) but still i am getting errors... here is what i have in my MvcSiteMapProviderContainerInitializer

    public static void SetUp(Container container)
        {
            bool securityTrimmingEnabled = false;
            bool enableLocalization = true;
            string absoluteFileName = HostingEnvironment.MapPath("~/Mvc.sitemap");
            TimeSpan absoluteCacheExpiration = TimeSpan.FromMinutes(5);
            string[] includeAssembliesForScan = new string[] { "testsitemap" };

// Extension to allow resolution of arrays by GetAllInstances (natively based on IEnumerable).
// source from: https://simpleinjector.codeplex.com/wikipage?title=CollectionRegistrationExtensions
            AllowToResolveArraysAndLists(container);

            var currentAssembly = typeof(MvcSiteMapProviderContainerInitializer).Assembly;
            var siteMapProviderAssembly = typeof(SiteMaps).Assembly;
            var allAssemblies = new Assembly[] { currentAssembly, siteMapProviderAssembly };
            var excludeTypes = new Type[]
                {
                    typeof (SiteMapNodeVisibilityProviderStrategy),
                    typeof (SiteMapXmlReservedAttributeNameProvider),
                    typeof (SiteMapBuilderSetStrategy),
                    typeof (ControllerTypeResolverFactory),

// Added 2013-06-28 by eric-b to avoid default singleton registration:
                    typeof(XmlSiteMapController),

// Added 2013-06-28 by eric-b for SimpleInjector.Verify method:
                    typeof(PreservedRouteParameterCollection),
                    typeof(MvcResolver),
                    typeof(MvcSiteMapProvider.SiteMap),
                    typeof(MetaRobotsValueCollection),
                    typeof(RoleCollection),
                    typeof(SiteMapPluginProvider),
                    typeof(ControllerTypeResolver),
                    typeof(RouteValueDictionary),
                    typeof(AttributeDictionary)

                    ,typeof(SiteMapNodeCreator)
                };
            var multipleImplementationTypes = new Type[]
                {
                    typeof (ISiteMapNodeUrlResolver),
                    typeof (ISiteMapNodeVisibilityProvider),
                    typeof (IDynamicNodeProvider)
                };

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

// Multiple implementations of strategy based extension points
            CommonConventions.RegisterAllImplementationsOfInterfaceSingle(
                (interfaceType, implementationTypes) => container.RegisterAll(interfaceType, implementationTypes),
                multipleImplementationTypes,
                allAssemblies,
                new Type[0],
                "^Composite");

            container.Register<XmlSiteMapController>();

// Visibility Providers
            container.RegisterSingle<ISiteMapNodeVisibilityProviderStrategy>(() =>
                                                                       new SiteMapNodeVisibilityProviderStrategy(
                                                                           container.GetAllInstances
                                                                               <ISiteMapNodeVisibilityProvider>().
                                                                               ToArray(), string.Empty));

// Pass in the global controllerBuilder reference
            container.RegisterSingle<ControllerBuilder>(() => ControllerBuilder.Current);

            container.RegisterSingle<IControllerBuilder, ControllerBuilderAdaptor>();

            container.RegisterSingle<IBuildManager, BuildManagerAdaptor>();

            container.RegisterSingle<IControllerTypeResolverFactory>(() =>
                                                               new ControllerTypeResolverFactory(new string[0],
                                                                                                 container.GetInstance
                                                                                                     <IControllerBuilder
                                                                                                     >(),
                                                                                                 container.GetInstance
                                                                                                     <IBuildManager>()));

// Configure Security
            container.RegisterAll<IAclModule>(typeof(AuthorizeAttributeAclModule), typeof(XmlRolesAclModule));
            container.RegisterSingle<IAclModule>(() => new CompositeAclModule(container.GetAllInstances<IAclModule>().ToArray()));

// Setup cache




            container.RegisterSingle<System.Runtime.Caching.ObjectCache>(() => System.Runtime.Caching.MemoryCache.Default);
            container.RegisterSingleOpenGeneric(typeof(ICacheProvider<>), typeof(RuntimeCacheProvider<>));
            container.RegisterSingle<ICacheDependency>(() => new RuntimeFileCacheDependency(absoluteFileName));

            container.RegisterSingle<ICacheDetails>(() => new CacheDetails(absoluteCacheExpiration, TimeSpan.MinValue, container.GetInstance<ICacheDependency>()));

// Configure the visitors
            container.RegisterSingle<ISiteMapNodeVisitor, UrlResolvingSiteMapNodeVisitor>();


// Prepare for the sitemap node providers
            container.RegisterSingle<ISiteMapXmlReservedAttributeNameProvider>(
                () => new SiteMapXmlReservedAttributeNameProvider(new string[0]));

            container.RegisterSingle<IXmlSource>(() => new FileXmlSource(absoluteFileName));


            // Register the sitemap node providers
            container.RegisterSingle<XmlSiteMapNodeProvider>(() => container.GetInstance<XmlSiteMapNodeProviderFactory>()
                .Create(container.GetInstance<IXmlSource>()));
            container.RegisterSingle<ReflectionSiteMapNodeProvider>(() => container.GetInstance<ReflectionSiteMapNodeProviderFactory>()
                .Create(includeAssembliesForScan));

            // Register your custom sitemap node provider
            container.RegisterSingle<ISiteMapNodeProvider, CustomSiteMapNodeProvider>();

            // Register the collection of sitemap node providers (including the custom one)
            container.RegisterSingle<ISiteMapBuilder>(() => container.GetInstance<SiteMapBuilderFactory>()
                .Create(new CompositeSiteMapNodeProvider(
                    container.GetInstance<XmlSiteMapNodeProvider>(),
                    container.GetInstance<ReflectionSiteMapNodeProvider>(),
                    container.GetInstance<CustomSiteMapNodeProvider>())));


            container.RegisterAll<ISiteMapBuilderSet>(ResolveISiteMapBuilderSets(container, securityTrimmingEnabled, enableLocalization));
            container.RegisterSingle<ISiteMapBuilderSetStrategy>(() => new SiteMapBuilderSetStrategy(container.GetAllInstances<ISiteMapBuilderSet>().ToArray()));
        }

        private static IEnumerable<ISiteMapBuilderSet> ResolveISiteMapBuilderSets(Container container, bool securityTrimmingEnabled, bool enableLocalization)
        {
            yield return new SiteMapBuilderSet(
                "default",
                securityTrimmingEnabled,
                enableLocalization,
                container.GetInstance<ISiteMapBuilder>(),
                container.GetInstance<ICacheDetails>());
        }

        private static void AllowToResolveArraysAndLists(Container container)
        {
            container.ResolveUnregisteredType += (sender, e) =>
            {
                var serviceType = e.UnregisteredServiceType;

                if (serviceType.IsArray)
                {
                    RegisterArrayResolver(e, container,
                        serviceType.GetElementType());
                }
                else if (serviceType.IsGenericType &&
                    serviceType.GetGenericTypeDefinition() == typeof(IList<>))
                {
                    RegisterArrayResolver(e, container,
                        serviceType.GetGenericArguments()[0]);
                }
            };
        }

        private static void RegisterArrayResolver(UnregisteredTypeEventArgs e, Container container, Type elementType)
        {
            var producer = container.GetRegistration(typeof(IEnumerable<>)
                .MakeGenericType(elementType));
            var enumerableExpression = producer.BuildExpression();
            var arrayMethod = typeof(Enumerable).GetMethod("ToArray")
                .MakeGenericMethod(elementType);
            var arrayExpression = Expression.Call(arrayMethod, enumerableExpression);
            e.Register(arrayExpression);
        }
    }

but still i get the following exception:

No registration for type DynamicSiteMapNodeBuilder could be found and an implicit registration could not be made. The constructor of the type DynamicSiteMapNodeBuilder contains the parameter of type ISiteMapNodeCreator with name 'siteMapNodeCreator' that is not registered. Please ensure ISiteMapNodeCreator is registered in the container, or change the constructor of DynamicSiteMapNodeBuilder.

解决方案

First of all, to integrate with an existing DI setup, you should install MvcSiteMapProvider.MVC4.DI.SimpleInjector.Modules instead of MvcSiteMapProvider.MVC4.DI.SimpleInjector. You can downgrade by running this command from package manager console:

PM> Uninstall-Package -Id MvcSiteMapProvider.MVC4.DI.SimpleInjector

Be sure NOT to uninstall any dependencies. This will ensure that you don't have 2 sets of DI initialization code in your project - there should only be 1 for the entire application.

Next, you need to wire up for DI as well as some other initialization code required by MvcSiteMapProvider. The readme file contains instructions how to do this. Here is how you would do it with your existing configuration.

public static void Initialize()
{
    Injection.Global = new Container();
    InitializeContainer(Injection.Global);
    Injection.Global.RegisterMvcControllers(Assembly.GetExecutingAssembly());
    Injection.Global.RegisterMvcAttributeFilterProvider();
    Injection.Global.Verify();
    DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(Injection.Global));
}

private static void InitializeContainer(Container container)
{
    // Setup configuration of DI (required)
    MvcSiteMapProviderContainerInitializer.SetUp(container);

    // Setup global sitemap loader (required)
    MvcSiteMapProvider.SiteMaps.Loader = container.GetInstance<ISiteMapLoader>();

    // Check all configured .sitemap files to ensure they follow the XSD for MvcSiteMapProvider (optional)
    var validator = container.GetInstance<ISiteMapXmlValidator>();
    validator.ValidateXml(HostingEnvironment.MapPath("~/Mvc.sitemap"));

    // Register the Sitemaps routes for search engines (optional)
    XmlSiteMapController.RegisterRoutes(RouteTable.Routes); // NOTE: You can put this in your RouteConfig.cs file if desired.

    //... register some other stuff for your project here ...
}

If the /sitemap.xml endpoint doesn't work, you may also need to add this line to register the XmlSiteMapController:

Injection.Global.RegisterMvcControllers(typeof(MvcSiteMapProvider.SiteMaps).Assembly);

To implement ISiteMapNodeProvider, there is an example here: MvcSiteMapProvider ISiteMapBuilder in conjunction with IDynamicNodeProvider.

To register your custom ISiteMapNodeProvider, you just need to ensure it gets added to the constructor of SiteMapBuilder. You can also exclude the existing SiteMapNodeProviders from the code below depending on your needs.

// Register the sitemap node providers
container.RegisterSingle<XmlSiteMapNodeProvider>(() => container.GetInstance<XmlSiteMapNodeProviderFactory>()
    .Create(container.GetInstance<IXmlSource>()));
container.RegisterSingle<ReflectionSiteMapNodeProvider>(() => container.GetInstance<ReflectionSiteMapNodeProviderFactory>()
    .Create(includeAssembliesForScan));

// Register your custom sitemap node provider
container.RegisterSingle<ISiteMapNodeProvider, CustomSiteMapNodeProvider>();

// Register the collection of sitemap node providers (including the custom one)
container.RegisterSingle<ISiteMapBuilder>(() => container.GetInstance<SiteMapBuilderFactory>()
    .Create(new CompositeSiteMapNodeProvider(
        container.GetInstance<XmlSiteMapNodeProvider>(), 
        container.GetInstance<ReflectionSiteMapNodeProvider>(), 
        container.GetInstance<CustomSiteMapNodeProvider>())));

Do note that IDynamicNodeProvider (which is documented) does almost exactly the same thing as ISiteMapNodeProvider, so you could use that option instead. There are 3 main differences:

  1. With IDynamicNodeProvider, you must create a "template" node that defines the dynamicNodeProvider attribute, and the template node itself won't be included in the SiteMap, so it must be used in conjunction with a ISiteMapNodeProvider implementation that processes the dynamic nodes (the built-in ISiteMapNodeProviders do this automatically).
  2. IDynamicNodeProvider doesn't need to be part of the DI setup because it is already processed by both XmlSiteMapNodeProvider and ReflectionSiteMapNodeProvider.
  3. With ISiteMapNodeProvider, you are working directly with the ISiteMapNode object, with IDynamicNodeProvider you are working with an abstraction (DynamicNodeProvider) and there is a conversion that happens automatically.

About SimpleInjector.Verify

If you want Verify() to work, you need to add the following to the excludeTypes array in the MvcSiteMapProviderContainerInitializer.

typeof(SiteMapNodeCreator),
typeof(DynamicSiteMapNodeBuilder)

I have added them to the module and will be in the next version of the Nuget package, but these modules do not update so you have to do it manually.

Note that the Verify() method tries to create an instance of everything that is registered with the container - including objects that never get created by the container in the real world. Therefore, if you use the Verify() method you have to be more diligent that something is not accidentally registered. This makes convention-based registration more difficult to do.

这篇关于如何实现自定义SiteMapNodeProvider的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆