简体   繁体   English

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

[英]Should asp menu items be bound for every page request

The asp menu control is in the master page. asp菜单控件位于母版页中。 Its datasource is a web.sitemap file. 它的数据源是一个web.sitemap文件。 This file has all the items/Pages declared as nodes, initially. 该文件最初具有声明为节点的所有项目/页面。 I have written this code to remove the items from the menu based on the user permissions, after user logs in. 用户登录后,我已根据用户权限编写了此代码以从菜单中删除项目。

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

The reason for the session variable is - The menuitemdatabound fires for every refresh/page request clicks, and I wanted the menu to be loaded only once for a user session. 会话变量的原因是-每次刷新/页面请求单击都会触发menuitemdatabound,并且我希望对于用户会话只加载一次菜单。

PROBLEM: 问题:

The 'Remove Item' code works fine. “删除项目”代码可以正常工作。 When the user logs in, the menu items do not show as desired. 当用户登录时,菜单项不会按预期显示。 But when he clicks on an existing item to move to another page, All the menus appear again in the menubar. 但是,当他单击现有项目以移至另一页时,所有菜单再次出现在菜单栏中。

Why is this happening. 为什么会这样呢? Should I allow the menuitemdatabound event everytime a page is refreshed or new url requested. 每次刷新页面或请求新的URL时,是否应允许menuitemdatabound事件。 Thats not right.is it?. 那不对。是吗? But any other way around? 但是还有其他办法吗? or i could just remove the session condition. 或者我可以删除会话条件。

using C# 使用C#

TRIED THIS: 尝试此:

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

If you are using xml sitemap, there is another way to make it. 如果您使用的是XML网站地图,则可以使用另一种方法。 Asp.Net has mechanism to override site map logic. Asp.Net具有覆盖站点地图逻辑的机制 There is base SiteMapProvider , and default implementation XmlSiteMapProvider . 有基础SiteMapProvider和默认实现XmlSiteMapProvider Base SiteMapProvider has IsAccessibleToUser . 基本SiteMapProvider具有IsAccessibleToUser You can create own sitemap provider like this: 您可以这样创建自己的站点地图提供程序:

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

Then you can specify it in web.config: 然后,您可以在web.config中指定它:

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

And then when Asp.Net will render menu based on sitemap, it will call IsAccessibleToUser each time for each user to verify that it has access to it. 然后,当Asp.Net将基于站点地图呈现菜单时,它将每次为每个用户调用IsAccessibleToUser,以验证其是否有权访问它。 And if you return false in that method, then this node and it's children will be hidden. 如果在该方法中返回false,则该节点及其子节点将被隐藏。

UPDATE1 UPDATE1

I've updated code to reflect original idea of binding. 我更新了代码以反映绑定的原始思想。 For testing I used such web.sitemap 为了测试,我使用了这样的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>

Here is my test roles: 这是我的测试角色:

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

Also securityTrimmingEnabled="true" was added to web.config in sample above. 还在上面的示例中,将securityTrimmingEnabled =“ true”添加到了web.config中。 Now when it checks for each node. 现在,当它检查每个节点时。 If node hasn't access based on tblDetail from session, then IsAccessibleNode returns false, and this node and all subnodes are hidden on UI. 如果节点无法从会话中基于tblDetail进行访问,则IsAccessibleNode返回false,并且该节点和所有子节点都隐藏在UI上。 It will execute this method for each node. 它将对每个节点执行此方法。 In my test case only Default.aspx and SubDefault1.aspx nodes were displayed, as I specified only two FormIDs 1, 11. So MySiteMapProvider displayed only them. 在我的测试案例中,仅显示Default.aspx和SubDefault1.aspx节点,因为我仅指定了两个FormID 1、11。因此MySiteMapProvider仅显示它们。

UPDATE2 Added aspx UI that i used UPDATE2添加了我使用的aspx UI

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

UPDATE 3 更新3

I've added new attribute to web.sitemap - isParent. 我已经将新属性添加到web.sitemap-isParent。 You can specify it in nodes that should be hidden, if all childs are not accessible. 如果无法访问所有子节点,则可以在应隐藏的节点中指定它。 And also I've updated code for provider to use this isParent node. 而且我还更新了提供程序的代码以使用此isParent节点。

after successful login you can rebind the menu 成功登录后,您可以重新绑定菜单

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

if(mainMenu!=null)

{ 
   mainMenu.DataBind();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM