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

时间:2016-07-15 06:41:16

标签: c# asp.net-mvc-5 mvcsitemapprovider

我使用C#注释配置MvcSiteMapProvider而不是XML。我根据文档实现了自定义可见性提供程序。我从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)会返回true。我希望FilteredSiteMapNodeVisibilityProvider将处理Visibility属性并返回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;
    }

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

1 个答案:

答案 0 :(得分:1)

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

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

至于提高可视性和通用性,这很难做到,因为每个人都有不同的可见性要求。可见性提供者的目的是实现您自己的可见性要求。 FilteredSiteMapNodeVisibilityProvider具有尽可能通用的特点,如果不符合您的要求,您需要定制。

请注意,通过将VisibilityProvider设置为自定义可见性提供程序类的类型字符串,您可以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作为shown here来完成。

请注意,如果需要,可以继承此类以与内部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"" }")]

另请注意,还有许多其他方法可以控制可见性,包括security trimming,自定义模板(或创建新模板并明确指定HTML帮助程序中的templateName),甚至创建/Views/Shared/DisplayTemplates/文件夹custom HTML helpers