First of all, 1 SiteMap for each user is possible, but it will not scale very well - in fact, it largely defeats the goal of creating a site map. I would not recommend this approach if you are not sure that your site will not have more than several tens of simultaneous users, you will have less than several hundred pages on the site, and you have additional resources on the server.
There are more scalable options to make the nodes visible / invisible according to which the user is logged in.
- Use Security Crop . When it is turned on, it automatically works only by properly setting up MVC protection using AuthorizeAttribute . AuthorizeAttribute has full role support. You can also inherit AuthorizeAttribute to add custom security logic if you need to.
- Use custom visibility providers to control whether each node is visible or invisible according to user criteria.
- Set up embedded HTML helpers (by changing templates in the
/Views/Shared/DisplayTemplates/ ) or create custom HTML helpers to dynamically load links per request for each user, in addition to links from a SiteMap instance.
None of these approaches require an external DI.
The recommended approach is to load all the nodes in SiteMap that every user can get, and then use security trimming to make the nodes for the current user invisible in the user interface. You can force the cache to reload when data changes using SiteMapCacheReleaseAttribute to make the dynamic nodes displayed in the user interface immediately after adding them to the data source.
With this in mind, if you still want to follow the path you are currently in, you have installed the wrong NuGet package. The way to load dependencies is that you need exactly 1 root composition in your project (i.e. one instance of WindsorContainer). Since you already have the composition root in your project, you only need to install the MvcSiteMapProvider module module for Windsor, and then manually add the module to the Windsor configuration by adding a few lines of code. You can upgrade to a package of modules only by running this command in the package manager console:
PM> Uninstall-Package MvcSiteMapProvider.MVC5.DI.Windsor
Then search where new WindsorContainer() declared in your project, and add the MvcSiteMapProvider module to the DI configuration.
// Create the DI container (typically part of your DI setup already) var container = new WindsorContainer(); // Your existing DI configuration should typically be here... // Setup configuration of DI container.Install(new MvcSiteMapProviderInstaller()); // Required container.Install(new MvcInstaller()); // Required by MVC. Typically already part of your setup (double check the contents of the module). // Setup global sitemap loader (required) MvcSiteMapProvider.SiteMaps.Loader = container.Resolve<ISiteMapLoader>(); // Check all configured .sitemap files to ensure they follow the XSD for MvcSiteMapProvider (optional) var validator = container.Resolve<ISiteMapXmlValidator>(); validator.ValidateXml(HostingEnvironment.MapPath("~/Mvc.sitemap")); // Register the Sitemaps routes for search engines (optional) XmlSiteMapController.RegisterRoutes(RouteTable.Routes);
If you make sure that there is only one instance of WindsorConntainer for the entire project and add the above code, you must have a working DI configuration.
To load 1 SiteMap for each user, you need to create your own ISiteMapCacheKeyGenerator, which returns a different row for each user.
public class UserSiteMapCacheKeyGenerator : ISiteMapCacheKeyGenerator { public virtual string GenerateKey() { var context = HttpContext.Current; if (context.User.Identity.IsAuthenticated) {
And add it by editing the Windsor module in /DI/Windsor/Installers/MvcSiteMapProviderInstaller.cs .
var excludeTypes = new Type[] {
It remains only to use dynamic node providers or implementations of ISiteMapNodeProvider to dynamically provide nodes to the user. If you configured it above, you can get the username through the SiteMap.CacheKey property.
public class SomeDynamicNodeProvider : DynamicNodeProviderBase { public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node) {
And finally, add your βtemplateβ nodes to your configuration to load dynamic nodes.
// Set a key explicitly to attach the dynamic nodes to. // The key property here corresponds to the ParentKey property of the dynamic node. <mvcSiteMapNode title="Home" controller="Home" action="Index" key="Home"> // Use a "dummy" node for each dynamic node provider. This node won't be in the SiteMap. <mvcSiteMapNode dynamicNodeProvider="NamespaceName.SomeDynamicNodeProivder, AssemblyName"/> </mvcSiteMapNode>