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

本文关键字:可见性 注释 MvcSiteMapProvider 指令 不起作用 自定义 实现 程序 | 更新日期: 2023-09-27 17:57:13

我正在使用 C# 注释而不是通过 XML 来配置MvcSiteMapProvider。我根据文档实现了自定义可见性提供程序。我的课程来自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在菜单中的可见性时(又名 (string)sourceMetadata["HtmlHelper"] == "MvcSiteMapProvider.Web.Html.SiteMapPathHelper" ),base.IsVisible(node, sourceMetadata)返回true。我希望FilteredSiteMapNodeVisibilityProvider将处理Visibility属性并返回false,看到此视图应仅出现在站点地图中。

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

    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内部处理。如何实现?

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

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

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

至于使可见性"普遍",这很难做到,因为每个人都有不同的可见性要求。可见性提供程序的目的是实现您自己的可见性要求。 FilteredSiteMapNodeVisibilityProvider尽可能通用,如果这不符合您的要求,则需要自定义。

请注意,您可以通过将VisibilityProvider设置为自定义可见性提供程序类的类型字符串来覆盖特定节点的默认可见性提供程序。

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

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

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

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"" }")]

另请注意,还有许多其他方法可以控制可见性,包括安全修整、自定义 /Views/Shared/DisplayTemplates/ 文件夹中的模板(或创建新模板并在 HTML 帮助程序中显式指定模板名称),甚至创建自定义 HTML 帮助程序。