简体   繁体   English

实现自定义可见性提供程序时,注释中的MvcSiteMapProvider Visibility指令不起作用

[英]MvcSiteMapProvider Visibility directives in annotation doesn't work when implementing custom visibility provider

I'm configuring MvcSiteMapProvider with C# annotations and not through XML . 我正在使用C#注释而不是通过XML配置MvcSiteMapProvider I implemented a custom visibility provider based on the documentation. 我根据文档实现了自定义可见性提供程序。 I derive my class from FilteredSiteMapNodeVisibilityProvider : 我从FilteredSiteMapNodeVisibilityProvider派生我的课程:

public class CustomVisibilityProvider: FilteredSiteMapNodeVisibilityProvider
{
    public override bool IsVisible(ISiteMapNode node, IDictionary<string, object> sourceMetadata)
    {
        if (node.Attributes.Keys.Contains("customVisibility"))
        {
            string customVisibility = (string)node.Attributes["customVisibility"];
            if (!string.IsNullOrEmpty(customVisibility))
            {
                customVisibility = customVisibility.Trim();
                ...
                var criteria = ...
                return criteria && base.IsVisible(node, sourceMetadata);
            }
        }

        return base.IsVisible(node, sourceMetadata);
    }
}

My Controller's view: 我的控制器的视图:

[MvcSiteMapNode(Title = "My View", ParentKey = "ParentController", Key = "MyView", Order = 922, PreservedRouteParameters = "id", Attributes = @"{ ""Visibility"": ""SiteMapPathHelper,!*"" }")]
public ActionResult MyView(int? id)
{
    return ViewForEntity(id);
}

As we can see I didn't use my own customVisibility attribute with this view, but I'd like to use the standard Visibility attributes. 如我们所见,我没有在此视图中使用自己的customVisibility属性,但是我想使用标准的Visibility属性。 This particular view shouldn't appear in the menu or elsewhere, except in the SiteMap . 除了SiteMap之外,此特定视图不应出现在菜单中或其他地方。

The problem is that when this view's SiteMapNode is examined for visibility in the menu (aka (string)sourceMetadata["HtmlHelper"] == "MvcSiteMapProvider.Web.Html.SiteMapPathHelper" ), the base.IsVisible(node, sourceMetadata) returns true . 问题是,当检查此视图的SiteMapNode在菜单中的可见性(aka (string)sourceMetadata["HtmlHelper"] == "MvcSiteMapProvider.Web.Html.SiteMapPathHelper" )时, base.IsVisible(node, sourceMetadata)返回true I'd expect that the FilteredSiteMapNodeVisibilityProvider will handle the Visibility attribute and return false , seeing that this view should only appear in the SiteMap. 我希望FilteredSiteMapNodeVisibilityProvider将处理Visibility属性并返回false ,因为看到此视图应仅出现在SiteMap中。

As a workaround I currently implemented my own check: 作为一种解决方法,我目前实施了自己的检查:

    private bool checkDefaultVisibility(ISiteMapNode node, IDictionary<string, object> sourceMetadata)
    {
        bool defaultVisibility = sourceMetadata["HtmlHelper"] == null || !node.Attributes.Keys.Contains("Visibility");
        if (sourceMetadata["HtmlHelper"] != null && node.Attributes.Keys.Contains("Visibility"))
        {
            var htmlHelper = (string)sourceMetadata["HtmlHelper"];  // Example: "MvcSiteMapProvider.Web.Html.SiteMapPathHelper"
            var helpersRules = ((string)node.Attributes["Visibility"]).Split(',');
            foreach(var helperRule in helpersRules)
            {
                if (helperRule != "!*" && htmlHelper.EndsWith("." + helperRule))
                {
                    defaultVisibility = true;
                    break;
                }
            }
        }
        return defaultVisibility;
    }

This is a method of my custom visibility provider. 这是我的自定义可见性提供程序的一种方法。 I hate it, because it's not universal, only handles specific cases. 我讨厌它,因为它不通用,只能处理特定情况。 At the same time I don't want to reinvent the wheel here. 同时,我不想在这里重新发明轮子。 I want Visibility to be handled by the MvcSiteMapProvider internals. 我希望由MvcSiteMapProvider内部处理Visibility How to achieve that? 如何实现呢?

Dictionary keys are case sensitive . 字典键区分大小写 The reason why FilteredSiteMapVisibilityProvider is not returning false is because you have set an attribute named Visibility instead of the expected name visibility . FilteredSiteMapVisibilityProvider不返回false的原因是因为您设置了名为Visibility的属性,而不是预期的名称visibility

[MvcSiteMapNode(Title = "My View", ParentKey = "ParentController", Key = "MyView", Order = 922, PreservedRouteParameters = "id", Attributes = @"{ ""visibility"": ""SiteMapPathHelper,!*"" }")]

As far as making visibility "universal", that would be difficult to do since everyone has different visibility requirements. 至于使可见性“通用”,这将是很难做到的,因为每个人都有不同的可见性要求。 The purpose of visibility providers is to implement your own visibility requirements. 可见性提供程序的目的是实现您自己的可见性要求。 FilteredSiteMapNodeVisibilityProvider is about as generic as it can get, and if that doesn't meet your requirements you need to go custom. FilteredSiteMapNodeVisibilityProvider与其通用性FilteredSiteMapNodeVisibilityProvider ,如果不符合您的要求,则需要自定义。

Do note you can override the default visibility provider for specific nodes by setting the VisibilityProvider to the type string of the custom visibility provider class. 请注意,您可以通过将VisibilityProvider设置为自定义可见性提供程序类的类型字符串来覆盖特定节点的默认可见性提供程序。

[MvcSiteMapNode(Title = "My View", ParentKey = "ParentController", Key = "MyView", Order = 922, PreservedRouteParameters = "id", VisibilityProvider = "MyNamespace.CustomVisibilityProvider, MyAssembly", Attributes = @"{ ""customVisibility"": ""foo"" }")]

If you need to use more than one visibility provider on the same node, it can be done using external DI and the CompositeSiteMapNodeVisibilityProvider as shown here . 如果需要在同一节点上使用多个可见性提供程序,则可以使用外部DI和CompositeSiteMapNodeVisibilityProvider来完成, 如下所示

Note that you can inherit this class for use with the internal DI container if you need to - but for internal DI you need a default constructor, so the types that it uses internally must be hard-coded into the constructor. 请注意,如果需要,您可以继承此类以与内部DI容器一起使用-但对于内部DI则需要一个默认构造函数,因此必须在内部使用它的类型硬编码到构造函数中。 But you can create as many of these classes as you need for your entire visibility configuration. 但是您可以为整个可见性配置创建所需数量的此类。

using MvcSiteMapProvider;
using MvcSiteMapProvider.Reflection;

public class MyCompositeVisibilityProvider : CompositeSiteMapNodeVisibilityProvider
{
    public MyCompositeVisibilityProvider()
        : base(
            typeof(MyCompositeVisibilityProvider).ShortAssemblyQualifiedName(), 

            // Note that the visibility providers are executed in
            // the order specified here, but execution stops when
            // the first visibility provider returns false.
            new FilteredSiteMapNodeVisibilityProvider(),
            new TrimEmptyGroupingNodesVisibilityProvider(),
            new CustomVisibilityProvider()
        )
    { }
}

And then calling it by using: 然后使用以下命令调用它:

[MvcSiteMapNode(Title = "My View", ParentKey = "ParentController", Key = "MyView", Order = 922, PreservedRouteParameters = "id", VisibilityProvider = "MyNamespace.MyCompositeVisibilityProvider, MyAssembly", Attributes = @"{ ""visibility"": ""SiteMapPathHelper,!*"", ""customVisibility"": ""foo"" }")]

Also note there are many other ways to control visibility including security trimming , customizing the templates (or creating new templates and specifying the templateName in the HTML helper explicitly) in the /Views/Shared/DisplayTemplates/ folder, or even creating custom HTML helpers . 还要注意,还有许多其他方法来控制可见性,包括安全调整 ,自定义模板(或在/Views/Shared/DisplayTemplates/文件夹中自定义模板(或在HTML帮助器中显式指定templateName),甚至创建自定义HTML帮助器

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM