Link to home
Start Free TrialLog in
Avatar of osiris247
osiris247Flag for United States of America

asked on

Menu control with web.sitemap

Hi Experts

I have a menu control which at present i have hardcoded the different items.  I wanted to change this to either an XMLdatasource or SQLdatasource.

I have had a play with both but dont seem to be able to have more than one root node.
I want to have say five root nodes, then have a few nodes under them.

The web.sitemap seems to allow only one root node.....had a look around but everything i find has either one root node only or is hardcoded like mine.

I want to have a dynamic menu bar, at present i have hardcoded every option then disable the ones not needed for the user.  An idea i had was to return an XML source from a web service.....What do you think? Any links for doing something this this would be good.  No point i guess if the above is not possible.....

Thanks
Steve
ASKER CERTIFIED SOLUTION
Avatar of deanvanrooyen
deanvanrooyen

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of osiris247

ASKER

Thanks....that is exactly what i wanted for the menu.  XML docs can only have one root node, i didnt spot that property!!

Just the dynamic thing to work on now....

Any links??

Steve
Avatar of levyuk
levyuk

You can use multiple sitemaps and change the sitemap for the individual user. I tried this once and it worked ok. There is some info on it here

http://www.levyuk.f2s.com/aspnet_sitemaps.php
thats ok but not dynamic enough.....

consider over 20 menu options....each user potentially different.  I do have user roles (custom not asp way) but this can be customised to break the generic set.

i have the permissions in SQL2005 database, flag for each option on the menu.  I need to either loop though enabling the correct node (doing at the mo) but i would like to not even show the nodes of the sitemap that the user doesnt have permission to use.



Steve
hi,

i do a similar thing with mysql.

I have a table called roles and a table called userinroles.

i am a newbie c# programmer, i have decided to use a method of creating roles that match the page name. therefore there is a role called mainportal.aspx, when the mainportal.aspx page loads it checks if the user is in the role of mainportal.aspx and if not then direct to a generic page. I have used roles as i have a page that allows admin users to select a system user and use a check box next to each role to select if they can "see" a page or not.

i use one master page the houses a treeview for navigation.

these are my steps - performed on every page load of EACH aspx page.

1 - check if the user is a system user (in role "SystemUser"), if not direct them out of the system

CheckNavigation(Session["loginname"].ToString(), "SystemUser");

   public  void CheckNavigation(string username, string rolename)
    {
        if (!IsUserInRole(username, rolename.ToLower())) //this will call a stored procedure to check if the record exists in the db
        {
            Server.Transfer("~/secure/content/Blank.aspx");
        }

    }

2 - get the name of the current executing page and check if the user is in that role - if not redirect them
//get the page name
        int start = HttpContext.Current.Request.CurrentExecutionFilePath.LastIndexOf('/') + 1;
        int lenght = HttpContext.Current.Request.CurrentExecutionFilePath.Length - start;
        string fileaspx = HttpContext.Current.Request.CurrentExecutionFilePath.Substring(start, lenght);
CheckNavigation(Session["loginname"].ToString(), fileaspx);

3 - manipulate the treeview, check each nodes aspx page and if the user is not in that "role" then remove the node from the treeview.
I found that this method below worked ok if called in the aspx page OnPreRenderComplete, because the treeview binding takes place after the page load is called as I used a sitemap and the binding is automatic. so if i tried to remove nodes in the page_load, the treeview would not be effected when the page loaded as the binding to the sitemap occured after the page_load occured.

CheckTreeLinks(Master, Session["loginname"].ToString()); // this is called in the aspx page so pass ref to master page for access to the treeview

the below is my main method of removing the treenodes. this should be redone with a better recursive method of itterating through the treenode collection of every treenode - that means that off the root note you have parent nodes, each parent node might have a few nodes below it,which inturn becomes like a sub parent node if it has child nodes below it. Another issue I found here is that when I used an Enumerator to go through the collection, i could not remove the node while in the while loop moving through the enumerator - this causes an error. so what I did was use an array to store the index of the nodes to remove and then go back through the parent level (2cnd level) and remove the nodes. then i do the same thing again with each parent nodes child nodes and do the check. I am aware that there are better ways of doing this but I just didnt have the time to do the research. i believe ther is a sitemapprovider class that can do this sort of functionality - not sure though. I want a better way of looping through every node in the treeview and just removing the node nice an cleanly, let me know if you find it....

using ...
using System.Collections;
using System.Collections.Specialized;

    ArrayList iremove; //array for index of removing nodes

    public void CheckTreeLinks(MasterPage mp,string username)
    {
            //index 0 = root node - home
            //index 1 = childnode       |__ calls
            //index 2 =                      |__news

            //check and modify treeview nav links
            // get ref to treeview

            TreeView myTV = (TreeView)mp.FindControl("TreeViewNav");
            TreeNodeCollection myNodeCollection = myTV.Nodes[0].ChildNodes;

            // Create an enumerator for the collection.
            IEnumerator myEnumerator = myNodeCollection.GetEnumerator();

            //get user roles
            string[] userroles = GetRolesForUser(username);

            //check all top level links
            //check if system user first
            if (!IsRoleInArray("SystemUser", userroles))
                myTV.Nodes.RemoveAt(0); //remove all links
            else //user can login so check sub links off root
            {
                int x = 0; // x holds index to remove treenode
                while (myEnumerator.MoveNext())
                {
                    try
                    {
                        //use the filename.aspx as the role check
                        string [] file = ((TreeNode)myEnumerator.Current).DataPath.Split('/');
                        if (!IsRoleInArray(file[file.Length -1], userroles))
                        {
                            iremove.Add(x);
                        }
                    }
                    catch (Exception e)
                    {
                        throw (e);
                    }
                    x++;
                }

                //remove links at specific index's stored in the iremove array.
                int[] check = (int[])iremove.ToArray(typeof(int)); //create int array easier to use below
                int index = 0;
                int c = 0;
                for (int i = 0; i < iremove.Count; i++)
                {
                    index = check[i];
                    myTV.Nodes[0].ChildNodes.RemoveAt(index - c);
                    c++;
                }

                //do sub links/ parent child nodes
                //remove the second level nodes
                //this is a temporary solution  for now to remove second level nodes(parent child nodes) and is different to the above method
                //start at the last node and move backwards when removing,this works and doesnt cause the enumerator to error out

                TreeNodeCollection myNodeCollection2 = myTV.Nodes[0].ChildNodes;

                // Create an enumerator for the collection.
                IEnumerator myEnumerator2 = myNodeCollection2.GetEnumerator();

                while (myEnumerator2.MoveNext())
                {
                    try
                    {

                        for (int n = ((TreeNode)myEnumerator2.Current).ChildNodes.Count - 1; n > -1; n--)
                        {
                            string[] file2 = ((TreeNode)myEnumerator2.Current).ChildNodes[n].DataPath.Split('/');
                            if (!IsRoleInArray(file2[file2.Length -1], userroles))
                            {
                                ((TreeNode)myEnumerator2.Current).ChildNodes.RemoveAt(n);

                            }
                        }
                    }
                    catch (Exception e)
                    {
                        throw (e);
                    }
               
                }

            }//else

    }