加载XML网站地图到MvcSiteMapProvider基于用户角色 [英] Load an XML sitemap into MvcSiteMapProvider based on user role

查看:434
本文介绍了加载XML网站地图到MvcSiteMapProvider基于用户角色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经安装了V4 MvcSiteMapProvider的,现在我要动态地加载地图。我的需求很简单 - 基于用户角色如当前登录的每个页面请求负载一个XML站点地图。 AdminSiteMap.xml和UserSiteMap.xml

I have installed v4 of MvcSiteMapProvider and now I want to load a sitemap dynamically. My needs are simple - load an XML sitemap on each page request based on the currently logged in user role eg. AdminSiteMap.xml and UserSiteMap.xml

看来,这是可以做到:

  • Using asp.net MVCSiteMapProvider v4 with 2 sitemap
  • https://github.com/maartenba/MvcSiteMapProvider/wiki/Multiple-Sitemaps-in-One-Application

所以基本上你需要使用DI来实现这一(矫枉过正恕我直言)。任何机会,这是可以做到的没有的一个DI?

So basically you need to use a DI to achieve this (overkill IMHO). Any chance this can be done without a DI?

所以当我使用ASP样板( http://www.aspnetboilerplate.com/ )我有温莎城堡作为我的DI

So as I am using ASP Boilerplate (http://www.aspnetboilerplate.com/) I have Castle Windsor as my DI.

因此​​,我安装通过的NuGetMvcSiteMapProvider MVC5温莎依赖注入配置。但是现在,当我运行应用程序,我得到了以下错误:

So I installed "MvcSiteMapProvider MVC5 Windsor Dependency Injection Configuration" via NuGet. However now when I run the app I get the following error:

该SiteMapLoader尚未初始化。

The SiteMapLoader has not been initialized.

Check the 'MvcSiteMapProvider_UseExternalDIContainer' setting in the AppSettings section of web.config.

If the setting is set to 'false', you will need to call the MvcSiteMapProvider.DI.Composer.Compose() method at the end of Application_Start in the Global.asax file. Alternatively, if you are using .NET 4.0 or higher you can install the MvcSiteMapProvider.MVCx NuGet package corresponding to your MVC version.

If the setting is set to 'true', you must set the SiteMaps.Loader property during Application_Start in Global.asax to an instance of the built-in SiteMapLoader type or a custom ISiteMapLoader instance. This can be achieved most easily by using your external DI container.

我并没有改变默认配置,已经证实,安装()方法被调用的公共类MvcSiteMapProviderInstaller:IWindsorInstaller ,因为它击中一个断点在那里。

I have not changed the default configuration and have confirmed that the Install() method is being called in public class MvcSiteMapProviderInstaller : IWindsorInstaller as it hits a breakpoint in there.

那么我在这里失踪,使这项工作。记得我试图做的是加载基于登录的用户在每次请求站点地图。

So what am I missing here to make this work. Remember all I am trying to do is load a SiteMap based on the logged in user on each request.

**** ****更新

**** UPDATE ****

尽管它可能不是优雅提议通过实施DI容器它并不需要一个庞大code量。见viggity的回答(约4一个向下)在@ 使用多个MvcSiteMaps

While it may not be elegant it did not require a huge amount of code as proposed by implementing a DI container. See viggity's answer (about the 4th one down) at @Using Multiple MvcSiteMaps

推荐答案

首先,每个用户1网站地图是可能的,但不会规模非常好 - 事实上,它pretty太多的失败作出的目的网站的地图。除非您确信您的网站将不会有超过几十个并发用户越多,你有不到几百页的网站上,我不会推荐这种方法,你必须在服务器上的可用内存外采空区。

First of all, 1 SiteMap per user is possible, but will not scale very well - in fact it pretty much defeats the purpose of making a site map. I wouldn't recommend this approach unless you are certain your site won't have more than a few dozen simultaneous users, you have less than a few hundred pages on the site, and you have gobs of extra memory available on the server.

有更具扩展性的选项,使根据该用户登录节点可见/不可见。

There are more scalable options to make nodes visible/invisible according to which user is logged in.


  • 使用安全修整。启用后,这才通过适当配置MVC安全与<一个自动工作href=\"http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute(v=vs.118).aspx\">AuthorizeAttribute. AuthorizeAttribute对角色的充分支持。您还可以继承AuthorizeAttribute添加自定义的安全逻辑,如果你需要。

  • 使用<一个href=\"https://github.com/maartenba/MvcSiteMapProvider/wiki/Advanced-Node-Visibility-with-ISiteMapNodeVisibilityProvider#creating-a-custom-sitemapnodevisibilityprovider\">custom可见提供商来控制根据自订标准每个节点是否可见或不可见。

  • 自定义内置的HTML辅助或构建自定义HTML佣工的动态加载每个请求的链接为每个用户除了链接从地图实例。

  • Use Security Trimming. When enabled, this works automatically just by properly configuring MVC security with the AuthorizeAttribute. AuthorizeAttribute has full support for roles. 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 custom criteria.
  • Customize the built in HTML helpers or build custom HTML helpers to dynamically load links per request for each user in addition to the links from the SiteMap instance.

这些方法都不需要外部DI

None of these approaches requires external DI.

建议的方法是向所有的节点加载到地图,每一个用户可能访问,则使用安全修整以使节点为当前用户在UI上不可见的。您可以强制缓存的重新加载时使用数据更改的<一个href=\"https://github.com/maartenba/MvcSiteMapProvider/wiki/Defining-sitemap-nodes-using-IDynamicNodeProvider#caching\">SiteMapCacheReleaseAttribute使<一个href=\"https://github.com/maartenba/MvcSiteMapProvider/wiki/Defining-sitemap-nodes-using-IDynamicNodeProvider\">dynamic节点将它们添加到您的数据源后,立即的在UI可见。

The recommended approach is to load all of the nodes into the SiteMap that every user could potentially access, then use security trimming to make the nodes for the current user invisible on the UI. You can force a reload of the cache when data changes by using the SiteMapCacheReleaseAttribute to make dynamic nodes visible on the UI immediately after adding them to your data source.

使用知识,如果你仍想继续向下的是当前的路径,你已经安装了错误的NuGet包。依赖注入的工作方式是,你需要在你的项目正好1根组成(也就是WindsorContainer的一个实例)。既然你已经在你的项目有一个根组成,您必须安装MvcSiteMapProvider的只有模块的包温莎,然后manualy加入code几行的模块添加到您的温莎配置。您可以通过运行在软件包管理器控制台命令降级到模块这只包:

With that knowledge, if you still would like to proceed down the path you are currently on, you have installed the wrong NuGet package. The way dependency injection works is that you need exactly 1 composition root in your project (that is, one instance of WindsorContainer). Since you already have a composition root in your project, you must install the MvcSiteMapProvider modules only package for Windsor and then manualy add the module to your Windsor configuration by adding a few lines of code. You can downgrade to the modules only package by running this command in Package Manager Console:

PM> Uninstall-Package MvcSiteMapProvider.MVC5.DI.Windsor

然后,寻找其中新WindsorContainer()在您的项目中声明和MvcSiteMapProvider模块添加到您的DI配置。

Then, search for where new WindsorContainer() is declared in your project and add the MvcSiteMapProvider module to your 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);

如果您确保只有1 WindsorConntainer项目范围的实例,并添加上述酌情code,你应该有一个工作DI配置。

If you ensure there is only 1 instance of WindsorConntainer project-wide and add the code above as appropriate, you should have a working DI configuration.

要加载每个用户1网站地图,你将需要返回为每个用户不同的字符串自定义ISiteMapCacheKeyGenerator。

To load 1 SiteMap per user, you will need to make a custom ISiteMapCacheKeyGenerator that returns a different string for each user.

public class UserSiteMapCacheKeyGenerator
    : ISiteMapCacheKeyGenerator
{
    public virtual string GenerateKey()
    {
        var context = HttpContext.Current;
        if (context.User.Identity.IsAuthenticated)
        {
            // Note: the way you retrieve the user name depends on whether you are using 
            // Windows or Forms authentication
            return context.User.Identity.Name;
        }
        else
        {
            return "default";
        }
    }
}

,并通过在 /DI/Windsor/Installers/MvcSiteMapProviderInstaller.cs 编辑温莎模块注入它。

var excludeTypes = new Type[] { 
    // Use this array to add types you wish to explicitly exclude from convention-based  
    // auto-registration. By default all types that either match I[TypeName] = [TypeName] or 
    // I[TypeName] = [TypeName]Adapter will be automatically wired up as long as they don't 
    // have the [ExcludeFromAutoRegistrationAttribute].
    //
    // If you want to override a type that follows the convention, you should add the name 
    // of either the implementation name or the interface that it inherits to this list and 
    // add your manual registration code below. This will prevent duplicate registrations 
    // of the types from occurring. 

    // Example:
    // typeof(SiteMap),
    // typeof(SiteMapNodeVisibilityProviderStrategy)
    typeof(SiteMapNodeUrlResolver),
    typeof(ISiteMapCacheKeyGenerator) // <-- add this line
};

// Code omitted here...


// Add this to the bottom of the module
container.Register(Component.For<ISiteMapCacheKeyGenerator>().ImplementedBy<UserSiteMapCacheKeyGenerator>();

剩下的唯一一件事就是使用<一个href=\"https://github.com/maartenba/MvcSiteMapProvider/wiki/Defining-sitemap-nodes-using-IDynamicNodeProvider\">dynamic节点提供或ISiteMapNodeProvider的实现每个用户动态地提供的节点。如果你将其设置为上面,可以通过SiteMap.CacheKey属性来获取用户名。

The only thing remaining is to use dynamic node providers or implementations of ISiteMapNodeProvider to dynamically supply the nodes per user. If you set it up as above, you can get the user name through the SiteMap.CacheKey property.

public class SomeDynamicNodeProvider : DynamicNodeProviderBase
{
    public override IEnumerable<DynamicNode> GetDynamicNodeCollection(ISiteMapNode node)
    {
        // Get the user name
        var user = node.SiteMap.CacheKey;

        // Entities would be your entity framework context class
        // or repository.
        using (var entities = new Entities())
        {
            // Add the nodes for the current user only
            foreach (var story in entities.Stories.Where(x => x.User == user)
            {
                DynamicNode dynamicNode = new DynamicNode();
                dynamicNode.Title = story.Title;

                // The key of the node that this node will be the child of.
                // This works best if you explicitly set the key property/attribute 
                // of the parent node.
                dynamicNode.ParentKey = "Home"; 
                dynamicNode.Key = "Story_" + story.Id;
                dynamicNode.Controller = "Story";
                dynamicNode.Action = "Details";

                // Add the "id" (or any other custom route values)
                dynamicNode.RouteValues.Add("id", story.Id);

                yield return dynamicNode;

                // If you have child nodes to the current node, you can
                // nest them here by setting their ParentKey property to 
                // the same value as the dynamicNode.Key and returning them
                // using yield return.
            }
        }
    }
}

最后,添加模板节点配置加载动态节点。

And finally, add your "template" nodes to your configuration to load the 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>

这篇关于加载XML网站地图到MvcSiteMapProvider基于用户角色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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