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

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

我正在使用 C# 注释而不是通过 XML 配置 MvcSiteMapProvider。我根据文档实现了自定义可见性提供程序。我的 class 来自 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);
    }
}

我的控制者的观点:

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

如我们所见,我没有在此视图中使用自己的 customVisibility 属性,但我想使用标准的 Visibility 属性。此特定视图不应出现在菜单或其他地方,SiteMap.

除外

问题是,当检查此视图的 SiteMapNode 在菜单中的可见性时 (a.k.a。(string)sourceMetadata["HtmlHelper"] == "MvcSiteMapProvider.Web.Html.SiteMapPathHelper"),base.IsVisible(node, sourceMetadata) returns true.我希望 FilteredSiteMapNodeVisibilityProvider 将处理 Visibility 属性和 return false,因为该视图应该只出现在 SiteMap 中。

作为解决方法,我目前实施了自己的检查:

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

这是我的自定义可见性提供程序的一种方法。我讨厌它,因为它不是通用的,只能处理特定情况。同时我不想在这里重新发明轮子。我希望 VisibilityMvcSiteMapProvider 内部处理。如何实现?

字典键区分大小写FilteredSiteMapVisibilityProvider 没有返回 false 的原因是因为您设置了一个名为 Visibility 的属性,而不是预期的名称 visibility.

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

就提高可见度而言 "universal",这很难做到,因为每个人都有不同的可见度要求。可见性提供者的目的是实现您自己的可见性要求。 FilteredSiteMapNodeVisibilityProvider 尽可能通用,如果不能满足您的要求,您需要定制。

请注意,您可以通过将 VisibilityProvider 设置为自定义可见性提供程序 class.

的类型字符串来 override the default visibility provider 特定节点
[MvcSiteMapNode(Title = "My View", ParentKey = "ParentController", Key = "MyView", Order = 922, PreservedRouteParameters = "id", VisibilityProvider = "MyNamespace.CustomVisibilityProvider, MyAssembly", Attributes = @"{ ""customVisibility"": ""foo"" }")]

如果您需要在同一节点上使用多个可见性提供程序,可以使用外部 DI 和 CompositeSiteMapNodeVisibilityProvider as shown here 来完成。

请注意,如果需要,您可以继承此 class 以便与内部 DI 容器一起使用 - 但对于内部 DI,您需要一个默认构造函数,因此它在内部使用的类型必须是硬编码的进入构造函数。但是您可以根据需要为整个可见性配置创建任意数量的这些 classes。

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()
        )
    { }
}

然后使用以下方式调用它:

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

另请注意,还有许多其他方法可以控制可见性,包括 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