If you are using xml sitemap, there is another way to make it. Asp.Net has mechanism to override site map logic. There is base SiteMapProvider, and default implementation XmlSiteMapProvider. Base SiteMapProvider has 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:
<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. And if you return false in that method, then this node and it's children will be hidden.
UPDATE1
I've updated code to reflect original idea of binding. For testing I used such 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. 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. 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.
UPDATE2 Added aspx UI that i used
<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1"></asp:Menu>
<asp:SiteMapDataSource ID="SiteMapDataSource1" Runat="Server"
StartFromCurrentNode="False" ShowStartingNode="True" />
UPDATE 3
I've added new attribute to 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.