【问题标题】:Should asp menu items be bound for every page request是否应该为每个页面请求绑定 asp 菜单项
【发布时间】:2014-01-07 18:43:54
【问题描述】:

asp 菜单控件位于母版页中。它的数据源是一个 web.sitemap 文件。 该文件最初将所有项目/页面声明为节点。我已经编写了这段代码,以便在用户登录后根据用户权限从菜单中删除项目。

protected void MyMenu_MenuItemDataBound(object sender, MenuEventArgs e) 
{
  if(Session["MenuLoaded"]==null)
  {
    SiteMapNode node = (SiteMapNode)e.Item.DataItem;
    bool deleteItem = true;
    if(lstRoles.Count==0)
       lstRoles = (List<tblDetail>)Session["sRoles"];
    if(!string.IsNullOrEmpty(node.Description))
     {
       foreach(var item in lstRoles)
        {
          if(Convert.ToInt32(node.Description)==item.FormId)
           {
             deleteItem = false;
             break;
           }
        }
        if(deleteItem)
         {
           if(e.Item.Parent !=null)
            {
              MenuItem mItem = e.Item.Parent;
              mItem.ChildItems.Remove(e.Item);
              if(mItem.ChildItems.Count==0)
                {
                  if(mItem.Parent !=null)
                   {
                     MenuItem Item = mItem.Parent;
                     Item.ChildItems.Remove(mItem);
                   }
                  else
                   {
                     Menu menu = (Menu)sender;
                     menu.Items.Remove(mItem);
                   }
                }
              else
                {
                  Menu menu = (Menu)sender;
                  menu.Items.Remove(e.Item);
                }
            }
         }
     }

  }
}

protected void MyMenu_DataBound(object sender, EventArgs e)
{
  Session["MenuLoaded"]=true;
}

会话变量的原因是 - 每次刷新/页面请求点击都会触发 menuitemdatabound,我希望菜单只为用户会话加载一次。

问题:

“删除项目”代码工作正常。当用户登录时,菜单项不会按需要显示。但是当他点击一个现有的项目移动到另一个页面时,所有的菜单再次出现在菜单栏中。

为什么会这样。每次刷新页面或请求新的 url 时,我是否应该允许 menuitemdatabound 事件。那不对。是吗?但是还有其他方法吗?或者我可以删除会话条件。

使用 C#

试过了:

page_load()
{
  if(Session["sMenuLoaded"]==null)
    lstRoles = (List<tblRoles>)Session["sMenuLoaded"];
  else
    {
      Menu mainMenu = (Menu)Session["sMenuLoaded"];
      mainMenu.DataBind();
    }

}

mymenu_menuitemdatabound()
{
  //  remains the same as above
}

mymenu_databound()
{
  Session["sMenuLoaded"] = (Menu)Page.Master.FindControl("menuBar");
}

【问题讨论】:

    标签: c# asp.net aspmenu


    【解决方案1】:

    如果您使用的是 xml 站点地图,还有另一种制作方法。 Asp.Net 有mechanism 来覆盖站点地图逻辑。有基础SiteMapProvider,默认实现XmlSiteMapProvider。 Base SiteMapProvider 有IsAccessibleToUser。您可以像这样创建自己的站点地图提供程序:

    public class MySiteMapProvider : XmlSiteMapProvider 
    {
        public override bool IsAccessibleToUser(HttpContext context, SiteMapNode node)
        {
            var lstRoles = (List<tblDetail>)context.Session["sRoles"];
    
            // when we are accessing ChildNodes, it will execute the same IsAccessibleToUser method for each of this sub nodes
            var childs = node.ChildNodes;
    
            var isParentNode = node["isParent"] == "true";
            if (childs.Count == 0 && isParentNode)
            {
                // it means that this is node is parent node, and all it sub nodes are not accessible, so we just return false to remove it
                return false;
            }
    
            if (string.IsNullOrWhiteSpace(node.Description))
                return true;
    
            var formId = Convert.ToInt32(node.Description);
            foreach (var item in lstRoles)
            {
                if (item.FormID == formId)
                    return true;
            }
    
            return false;
        }
    }
    

    然后可以在web.config中指定:

      <siteMap defaultProvider="myProvider">
          <providers>
              <add name="myProvider" securityTrimmingEnabled="true"  
              type="WebApplication5.MySiteMapProvider"  siteMapFile="web.sitemap" />
          </providers>
      </siteMap>
    

    然后当 Asp.Net 将基于站点地图呈现菜单时,它会为每个用户每次调用 IsAccessibleToUser 来验证它是否可以访问它。如果您在该方法中返回 false,则该节点及其子节点将被隐藏。

    更新1

    我更新了代码以反映最初的绑定理念。为了测试,我使用了这样的 web.sitemap

    <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
    <siteMapNode url="" title="Root">
        <siteMapNode url="Default.aspx" title="1"  description="1">
            <siteMapNode url="SubDefault.aspx" title="2"  description="11" />
            <siteMapNode url="SubDefault1.aspx" title="3"  description="12" />
        </siteMapNode>
        <siteMapNode url="Default2.aspx" title="2_1" isParent="true">
            <siteMapNode url="Default3.aspx" title="21" description="2"/>
        </siteMapNode>
    </siteMapNode>
    

    这是我的测试角色:

    Session["sRoles"] = new List<tblDetail>()
                        {
                            new tblDetail() { FormID = 12 }, 
                            new tblDetail() { FormID = 1 }
                        };
    

    在上面的示例中,securityTrimmingEnabled="true" 也被添加到 web.config 中。 现在当它检查每个节点时。如果节点没有基于会话中的 tblDetail 访问,则 IsAccessibleNode 返回 false,并且该节点和所有子节点都隐藏在 UI 上。它将为每个节点执行此方法。在我的测试用例中,只显示了 Default.aspx 和 SubDefault1.aspx 节点,因为我只指定了两个 FormID 1、11。所以 MySiteMapProvider 只显示了它们。

    更新2 添加了我使用的 aspx UI

    <asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1"></asp:Menu>
    <asp:SiteMapDataSource ID="SiteMapDataSource1" Runat="Server" 
         StartFromCurrentNode="False" ShowStartingNode="True" />
    

    更新 3

    我已向 web.sitemap 添加了新属性 - isParent。如果所有子节点都不可访问,您可以在应隐藏的节点中指定它。 而且我还更新了提供程序的代码以使用这个 isParent 节点。

    【讨论】:

    • 谢谢。但是配置文件将在客户端生成。可能有很多,每个都有不同的角色。所以硬编码不是一种选择。
    • 它不应该被硬编码。我已将如何使用数据库的示例、该自定义站点地图中当前页面的数据添加到我的答案中
    • 我看到了..“Administration”、“Admin”..对不起,我不明白。客户将为他的公司开发自己的个人资料/角色。许多个人资料都可以查看一个页面,而不仅仅是管理员。
    • WebApp.MySiteMapProvider 应该是 FullNamespaces.TypeName。如果 type 不在 Web 应用程序中,而是在附加的类库中,那么它应该包括这样的程序集名称:type="SomeNameSpace.MySiteMapProvider, SomeClassLibraryName"
    • 我已经更新了示例 :) 这只是建议,但是您可以将示例中的 isParent="true" 节点添加到根节点,然后如果所有子节点都被拒绝访问,那么这个不会显示根节点
    【解决方案2】:

    登录成功后可以重新绑定菜单

    Menu mainMenu=(Menu)Page.Master.FindControl("MyMenu");
    
    if(mainMenu!=null)
    
    { 
       mainMenu.DataBind();
    }
    

    【讨论】:

    • 您能否进一步解释一下 lil。我已经更新了我尝试过的内容
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-09
    • 1970-01-01
    • 2012-03-02
    • 2015-04-27
    • 1970-01-01
    • 1970-01-01
    • 2019-05-25
    相关资源
    最近更新 更多