应该为每个页面请求绑定asp菜单项

时间:2013-12-19 09:20:10

标签: c# asp.net aspmenu

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,我希望菜单只为用户会话加载一次。

问题:

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

为什么会这样。每次刷新页面或请求新网址时,我是否应该允许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");
}

2 个答案:

答案 0 :(得分:3)

如果您使用的是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,那么这个节点及其子节点将被隐藏。

<强> UPDATE1

我已更新代码以反映绑定的原始想法。为了测试,我使用了这样的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 }
                    };

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

<强> UPDATE2 添加了我使用的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节点的代码。

答案 1 :(得分:1)

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

Menu mainMenu=(Menu)Page.Master.FindControl("MyMenu");

if(mainMenu!=null)

{ 
   mainMenu.DataBind();
}