2013-11-07 4 views
0

Я пытаюсь адаптировать MvcSiteMapProvider для создания палитры на основе некоторой информации, хранящейся в базе данных.Как реализовать пользовательский SiteMapNodeProvider

Ответ на сообщение this был прозвучал многообещающе, поэтому я реализовал свой собственный SiteMapNodeProvider. Но тогда я не знал, как подключить их, поэтому вместо внедренного файла SiteMapNodeProvider используется статический xml-файл («Mvc.sitemap»).

Как я использую SimpleInjector в своем проекте, я назвал метод установки в моем уже существующем коде инициализации инъекции.

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-пакета), но все-таки я получать ошибки ... вот что я имею в моем 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); 
     } 
    } 

, но до сих пор я получаю следующее исключение:

Нет регистрации для типа DynamicSiteMapNo deBuilder может быть найден и неявная регистрация не может быть выполнена. Конструктор типа DynamicSiteMapNodeBuilder содержит параметр типа ISiteMapNodeCreator с именем «siteMapNodeCreator», который не зарегистрирован . Убедитесь, что ISiteMapNodeCreator зарегистрирован в контейнере или измените конструктор DynamicSiteMapNodeBuilder.

ответ

1

Прежде всего, чтобы интегрироваться с существующей установкой DI, вы должны установить MvcSiteMapProvider.MVC4.DI.SimpleInjector.Modules вместо MvcSiteMapProvider.MVC4.DI.SimpleInjector. Вы можете понизить, выполнив команду из пакета менеджера консоли:

PM> Uninstall-пакет -id MvcSiteMapProvider.MVC4.DI.SimpleInjector

Убедитесь, что не удалить какие-либо зависимости. Это гарантирует, что у вас нет двух наборов кода инициализации 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<ReflectionSiteMapNodeProvider>(), 
     container.GetInstance<CustomSiteMapNodeProvider>()))); 

Обратите внимание, что IDynamicNodeProvider (что документально) делает почти то же самое, как ISiteMapNodeProvider, так что вы можете использовать эту опцию вместо. Есть 3 основных отличия:

  1. С IDynamicNodeProvider, вы должны создать «шаблон» узел, который определяет атрибут dynamicNodeProvider, а сам узел шаблон не будет включен в SiteMap, поэтому он должен быть использован в сочетании с реализацией ISiteMapNodeProvider, которая обрабатывает динамические узлы (встроенные ISiteMapNodeProviders делают это автоматически).
  2. IDynamicNodeProvider не обязательно должен быть частью установки DI, поскольку он уже обрабатывается как XmlSiteMapNodeProvider, так и ReflectionSiteMapNodeProvider.
  3. С ISiteMapNodeProvider вы работаете непосредственно с объектом ISiteMapNode, при этом IDynamicNodeProvider работает с абстракцией (DynamicNodeProvider), и происходит автоматическое преобразование.

О SimpleInjector.Verify

Если вы хотите Verify() работать, вам необходимо добавить следующие строки в массиве excludeTypes в MvcSiteMapProviderContainerInitializer.

typeof(SiteMapNodeCreator), 
typeof(DynamicSiteMapNodeBuilder) 

Я добавил их в модуль и будет в следующей версии пакета NuGet, но эти модули не обновляются, так что вы должны сделать это вручную.

Обратите внимание, что метод Verify() пытается создать экземпляр всего, что зарегистрировано в контейнере, включая объекты, которые никогда не создаются контейнером в реальном мире. Поэтому, если вы используете метод Verify(), вам нужно быть более прилежным, чтобы что-то случайно не было зарегистрировано. Это затрудняет работу с регистрацией на основе конвенций.

+0

thx за вашу помощь, но я получаю следующее исключение при вызове verify(): Конфигурация недействительна. Не удалось создать экземпляр типа ISiteMapNodeCreator. Зарегистрированный делегат для типа ISiteMapNodeCreator бросил исключение. Никакой регистрации для типа SiteMapNodeCreator не найдено, и неявная регистрация не может быть выполнена. Конструктор типа SiteMapNodeCreator содержит параметр типа ISiteMap с именем «siteMap», которое не зарегистрировано. Убедитесь, что ISiteMap зарегистрирован в контейнере или изменил конструктор SiteMapNodeCreator. – r3try

+1

ISiteMapNodeCreator создан SiteMapNodeCreatorFactory, поэтому необходимо зарегистрировать только завод. Вероятно, вам нужно добавить исключение для typeof (SiteMapNodeCreator) в массив excludeTypes (а также могут быть добавлены другие типы). BTW - тестирование конфигурации не считается лучшей практикой, потому что оно не всегда находит проблемы в конфигурации: http://blog.ploeh.dk/2011/12/21/TestingContainerConfigurations/ – NightOwl888

+0

Я отредактировал свой вопрос. Как узнать, какие типы добавить в список игнорирования? не является ли пакет nuget настроенным для работы из коробки? (извините, что беспокою вас так много, но я просто не понимаю, как продолжить ...) – r3try

Смежные вопросы