加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net-mvc-4 – 如何实现自定义SiteMapNodeProvider

发布时间:2020-12-16 00:09:07 所属栏目:asp.Net 来源:网络整理
导读:我正在尝试调整MvcSiteMapProvider以基于存储在数据库中的一些信息创建面包屑. this帖子的答案听起来很有希望所以我实现了自己的SiteMapNodeProvider.但后来我不知道如何连接,所以使用新实现的SiteMapNodeProvider而不是静态xml文件(“Mvc.sitemap”). 当我
我正在尝试调整MvcSiteMapProvider以基于存储在数据库中的一些信息创建面包屑.

this帖子的答案听起来很有希望所以我实现了自己的SiteMapNodeProvider.但后来我不知道如何连接,所以使用新实现的SiteMapNodeProvider而不是静态xml文件(“Mvc.sitemap”).

当我在我的项目中使用SimpleInjector时,我在已经存在的注入初始化代码中调用了setup方法.

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 ...
    }

MvcSiteMapProviderContainerInitializer类由包创建:’Mvcsitemapprovider.mvc4.di.simpleinjector / 4.4.5′

有谁知道如何让我的项目使用新创建的SiteMapNodeProvider?
我在官方文件中找不到任何关于此的文件……

编辑:我尝试了你的建议(甚至删除旧的DI东西,只使用了nuget-package中的那个),但我仍然得到错误…
这是我在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,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",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,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);
        }
    }

但我仍然得到以下异常:

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.

解决方法

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

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

一定不要卸载任何依赖项.这将确保您的项目中没有2组DI初始化代码 – 整个应用程序应该只有1组.

接下来,您需要连接DI以及MvcSiteMapProvider所需的其他一些初始化代码. readme file包含如何执行此操作的说明.以下是使用现有配置的方法.

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 ...
}

如果/sitemap.xml端点不起作用,您可能还需要添加此行来注册XmlSiteMapController:

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

要实现ISiteMapNodeProvider,这里有一个例子:MvcSiteMapProvider ISiteMapBuilder in conjunction with IDynamicNodeProvider.

要注册自定义ISiteMapNodeProvider,您只需确保将其添加到SiteMapBuilder的构造函数中.您还可以根据需要从以下代码中排除现有的SiteMapNodeProviders.

// 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<CustomSiteMapNodeProvider>())));

请注意,IDynamicNodeProvider(已记录)与ISiteMapNodeProvider几乎完全相同,因此您可以使用该选项.主要有三个不同之处:

>使用IDynamicNodeProvider,您必须创建一个定义dynamicNodeProvider属性的“模板”节点,并且模板节点本身不会包含在SiteMap中,因此它必须与处理动态节点的ISiteMapNodeProvider实现一起使用(内置的ISiteMapNodeProviders自动执行此操作).
> IDynamicNodeProvider不需要成为DI设置的一部分,因为它已由XmlSiteMapNodeProvider和ReflectionSiteMapNodeProvider处理.
>使用ISiteMapNodeProvider,您直接使用ISiteMapNode对象,使用IDynamicNodeProvider处理抽象(DynamicNodeProvider)并且会自动进行转换.

关于SimpleInjector.Verify

如果要使Verify()工作,则需要将以下内容添加到MvcSiteMapProviderContainerInitializer中的excludeTypes数组中.

typeof(SiteMapNodeCreator),typeof(DynamicSiteMapNodeBuilder)

我已将它们添加到模块中,并将在Nuget包的下一个版本中,但这些模块不会更新,因此您必须手动执行此操作.

请注意,Verify()方法尝试创建向容器注册的所有内容的实例 – 包括永远不会被现实世界中的容器创建的对象.因此,如果您使用Verify()方法,则必须更加勤奋,以免意外注册.这使得基于约定的注册更加困难.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读