.NET Bind/update not always working or Update Panel hides errors

While at first, the titles may not seem related to each other but they are.

I fought this for a couple days. I have multiple listboxes, If you click an item in one, it changes the items in the second. 9 out of 10 times this would work but there were a few instances where the listbox would not change, even though in the code behind you can see the new data and it binds to the listbox. No errors are shown.

Searching through the web I ran into someone having a different issue but it was caused by the updatepanel, I have an updatepanel, lets disable it. As soon as I disabled the update panel, I received an error on my master page but it was about the listbox. In my code it was possible to try to highlight multiple items in the listbox but I had each box set to single. Once I fixed that, the data was now binding and updating. I enabled the updatepanel and Boom! all was working.

 

So if you come across any off the wall problems, first try disabling your updatepanel.

 

     

Indent Items in a Web Forms ListBox or Adding   to ListBox

Today I needed to create a listbox that had 3 levels of indent, with dynamic data. I didn’t want 3 columns but something like this:

This is level1 with no indent

This is level2 with indent

This is level 3 with indent

Using Listbox, if you add spaces they will just smash together because of most fonts (once shown on your website, it shows correct in your datatable). If you try to add “ ”, Since unlike some Controls, in listbox you can not turn on HTMLDecode so the Listbox will just show the text “  ”.

 

This fix for this is to add the htmldecode with the data using Server.HTMLDecode

Example:

 

Row 1 with no indent


dRow(0) = dr("SQLColumn1")

 

Row 2 with 1 set of indents


dRow(0) = (Server.HtmlDecode("      ")) & dr("SQLColumn2")

Row 3 with 2 set of indents


dRow(0) = (Server.HtmlDecode("      ")) & (Server.HtmlDecode("      ")) & dr("SQLColumn3") 

     

User.Identity.IsAuthenticated always False

After many hours and trying every example on the web, I finally found out why User.Identity.IsAuthenticated was always False. This was in the web.config:

<modules>
 <remove name="FormsAuthentication"/>
</modules>

Remove the “remove name” line and User.Identity.IsAuthenticated will finally be True

 

     

.net DropDownList (DDL) Not showing correct or showing first item everytime

Just a note about something I came across yesterday. I had a DDL that the selecteditem would be incorrect and many times no matter what I chose, the first item would show.

After many hours of trying to figure out what was happening, I cam across this for the SelectedValue Property

https://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.listcontrol.selectedvalue(v=vs.110).aspx

This property returns the Value property of the selected ListItem. The SelectedValue property is commonly used to determine the value of the selected item in the list control. If multiple items are selected, the value of the selected item with the lowest index is returned.

I was adding “true” or “false” to the selectedvalue property. So still needing a t/f I added a count to each resulting in true3 or false5 and then looking for the true/false with InStr.

 

     

Adding Multiple CollapsiblePanelExtender dynamically (in code behind)

Using Multiple CollapsiblePanelExtender’s

My task today was to create something that looked like an Accordion control but you could open multiple accordions (sections) at one time. While many online claim this is doable with the Accordion control, I couldn’t get it to work from the code behind so I decided to go with creating multiple Collapsible Panels.

There’s a great article by Suprotim Agarwal called ASP.NET AJAX CollapsiblePanelExtender – Tips and Tricks, this article get’s us 80% of the way in the section “Tip 5: How to add an ASP.NET AJAX CollapsiblePanelExtender dynamically?”.

Taking his code:


Imports AjaxControlToolkit

 Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
 ' Create Header Panel
 Dim panelHead As New Panel()
 panelHead.ID = "pH"
 panelHead.CssClass = "cpHeader"
 ' Add Label inside header panel to display text
 Dim lblHead As New Label()
 lblHead.ID = "lblHeader"
 panelHead.Controls.Add(lblHead)

 'Create Body Panel
 Dim panelBody As New Panel()
 panelBody.ID = "pB"
 panelBody.CssClass = "cpBody"
 ' Add Label inside body Panel to display text
 Dim lblB As New Label()
 lblB.ID = "lblBody"
 lblB.Text = "This panel was added dynamically"
 panelBody.Controls.Add(lblB)

 ' Create CollapsiblePanelExtender
 Dim cpe As New CollapsiblePanelExtender()
 cpe.TargetControlID = panelBody.ID
 cpe.ExpandControlID = panelHead.ID
 cpe.CollapseControlID = panelHead.ID
 cpe.ScrollContents = False
 cpe.Collapsed = True
 cpe.ExpandDirection = CollapsiblePanelExpandDirection.Vertical
 cpe.SuppressPostBack = True
 cpe.TextLabelID = lblHead.ID
 cpe.CollapsedText = "Click to Show Content.."
 cpe.ExpandedText = "Click to Hide Content.."

 Me.UpdatePanel1.ContentTemplateContainer.Controls.Add(panelHead)
 Me.UpdatePanel1.ContentTemplateContainer.Controls.Add(panelBody)
 Me.UpdatePanel1.ContentTemplateContainer.Controls.Add(cpe)

 End Sub

To create multiples we need to take the above code and loop through it adding +1 to each ID,  so instead of  panelHead.ID = “pH” we want  panelHead.ID = “pH” & p where at the end of each loop we add +1 to p.  We do this for each ID, so the code would look like this:

 


For num = 0 To header.Count - 1
' Create Header Panel
Dim panelHead As New Panel()
panelHead.ID = "pH" & p
panelHead.CssClass = "accordionHeader"
' Add Label inside header panel to display text
Dim lblHead As New Label()
lblHead.ID = "lblHeader" & p
lblHead.Text = header(num).ToString
panelHead.Controls.Add(lblHead)

'Create Body Panel
Dim panelBody As New Panel()
panelBody.ID = "pB" & p1
panelBody.CssClass = "accordionContent"
' Add Label inside body Panel to display text
Dim lblB As New Label()
lblB.ID = "lblBody" & p1
lblB.Text = body(num).ToString
panelBody.Controls.Add(lblB)

' Create CollapsiblePanelExtender
Dim cpe As New CollapsiblePanelExtender()
cpe.ID = "cpe" & r1
cpe.TargetControlID = panelBody.ID
cpe.ExpandControlID = panelHead.ID
cpe.CollapseControlID = panelHead.ID
cpe.ScrollContents = False
If opennum = 0 Then
cpe.Collapsed = False
Else
cpe.Collapsed = True
End If

cpe.ExpandDirection = CollapsiblePanelExpandDirection.Vertical
cpe.SuppressPostBack = True
cpe.TextLabelID = lblHead.ID
cpe.ExpandedText = header(num).ToString & "<div style='float: right; vertical-align: middle;'><input type='image' name='ImageCollapse" & num & "' id='ImageCol" & num & "' src='../images/collapse.jpg' alt='(Show Details...)' /></div>"
cpe.CollapsedText = header(num).ToString & "<div style='float: right; vertical-align: middle;'><input type='image' name='Imageexp" & num & "' id='ImageExp" & num & "' src='../images/expand_blue.jpg' alt='(Show Details...)' /></div>"

Me.UpdatePanel1.ContentTemplateContainer.Controls.Add(panelHead)
Me.UpdatePanel1.ContentTemplateContainer.Controls.Add(panelBody)
Me.UpdatePanel1.ContentTemplateContainer.Controls.Add(cpe)

p = p + 1
p1 = p1 + 1
r1 = r1 + 1
opennum = opennum + 1
Next

 

Above you’ll notice that we loop as many times as we have headers, for us , this was Category headers from SQL and then each accordion contained subcategories. From SQL we created an array of Category headers and a body array of all subcategories.

Technorati Tags: , , , ,

     

Adding Styles to Subgurim’s Google Maps Control (Code Behind)

The current version of Subgurim’s Google Maps Control has the ability to add styles to your Google Maps, but I wanted to go deeper and create a map style like seen at Snazzy Maps. There were a few hints on the Subgurim Forums but nothing with a complete answer.

The map style I liked was Subtle Grayscale

Call this sub after loading your map from your code behind


Private Sub ApplyMapStyle()
Dim sb As New StringBuilder()
GMap1.Add("ApplyMapStyle();", True)

sb.Append("var myMapStyle = [{")
sb.Append("featureType: ""landscape"",")
sb.Append("""stylers"": [")
sb.Append("{ ""visibility"": ""on"" },")
sb.Append("{ ""saturation"": -100 },")
sb.Append("{ ""lightness"": 60 }")
sb.Append("]},")

sb.Append("{")
sb.Append("featureType: ""poi"",")
sb.Append("""stylers"": [")
sb.Append("{ ""visibility"": ""simplified"" },")
sb.Append("{ ""saturation"": -100 },")
sb.Append("{ ""lightness"": 51 }")
sb.Append("]},")

sb.Append("{")
sb.Append("featureType: ""road.highway"",")
sb.Append("""stylers"": [")
sb.Append("{ ""visibility"": ""simplified"" },")
sb.Append("{ ""saturation"": -100 }")
sb.Append("]},")

sb.Append("{")
sb.Append("featureType: ""road.arterial"",")
sb.Append("""stylers"": [")
sb.Append("{ ""visibility"": ""on"" },")
sb.Append("{ ""saturation"": -100 },")
sb.Append("{ ""lightness"": 30 }")
sb.Append("]},")

sb.Append("{")
sb.Append("featureType: ""road.local"",")
sb.Append("""stylers"": [")
sb.Append("{ ""visibility"": ""on"" },")
sb.Append("{ ""saturation"": -100 },")
sb.Append("{ ""lightness"": 40 }")
sb.Append("]},")

sb.Append("{")
sb.Append("featureType: ""transit"",")
sb.Append("""stylers"": [")
sb.Append("{ ""visibility"": ""simplified"" },")
sb.Append("{ ""saturation"": -100 }")
sb.Append("]},")

sb.Append("{")
sb.Append("featureType: ""administrative.province"",")
sb.Append("""stylers"": [")
sb.Append("{ ""visibility"": ""off"" }")
sb.Append("]},")

sb.Append("{")
sb.Append("featureType: ""administrative.province"",")
sb.Append("elementType: ""geometry"",")
sb.Append("""stylers"": [")
sb.Append("{ ""visibility"": ""on"" },")
sb.Append("{ ""lightness"": -100 }")
sb.Append("]},")

sb.Append("{")
sb.Append("featureType: ""water"",")
sb.Append("elementType: ""labels"",")
sb.Append("""stylers"": [")
sb.Append("{ ""visibility"": ""on"" },")
sb.Append("{ ""saturation"": -100 },")
sb.Append("{ ""lightness"": -25 }")
sb.Append("]},")

sb.Append("{")
sb.Append("featureType: ""water"",")
sb.Append("elementType: ""geometry"",")
sb.Append("""stylers"": [")
sb.Append("{ ""saturation"": -97 },")
sb.Append("{ ""lightness"": -25 },")
sb.Append("{ ""hue"": ""#ffff00"" }")
sb.Append("]")

sb.Append("}];")

sb.Append("function ApplyMapStyle()")
sb.Append("{")
sb.Append("var mapType = new google.maps.StyledMapType(myMapStyle);")
sb.AppendFormat("{0}.mapTypes.set(""mymap"", mapType);", GMap1.GMap_Id)
sb.AppendFormat("{0}.setMapTypeId(""mymap"");", GMap1.GMap_Id)
sb.Append("}")

GMap1.Add(sb.ToString())
End Sub

Technorati Tags: , , ,

     

.Net Convert Your Site From PlainText Passwords to Salted Hashes

Why Change your passwords to Salted Hashes

I’ve had a site that for a long time has been on my TODO list to convert the site from using plaintext passwords to using passwords that are hashed and salted. No matter what the excuse, the truth is, it’s not really just your data that you’re protecting by encrypting your passwords, but it’s the user, since many still use the same password on many systems.

Our Conversion Steps

1. Build a command line application to convert all passwords in our SQL server to hashed data with salt.

2. Change current code in the site when a user has forgotten their password.

3. Change current code in site for when a new user is created.

4. Change current code in site for when a user wants to change their password.

5. Change the code for user login to except the plaintext password they enter, hash/salt it and compare it to what’s in the DB

 

Advice & Example sites:

While doing research on hashing and what/how to do it, I’m learned a couple things. 1. Don’t write your own encryption (You are not an expert!) 2. If you can decrypt the passwords back to plaintext then someone else probably can (in our code we will never be decryption but we’ll take what the user says is their password and encrypt it and compare it to what’s in the database)  3. Do not use MD5, while one of our example sites has the option, it’s just for example and for the same reason always salt your hashes (see: https://crackstation.net/ )

The 2 sites that I used to for code samples are:

1. The how to for salted hashes How to hash data with salt in C# or VB.NET

2. How to recover and reset the forgot/lost password in asp.net using activation link in email id

 

Converting All Current Passwords

To convert our current passwords from Plaintext to salted hash passwords we’ll need to build a small command line application to loop through the SQL table, encrypt, created the hash and salt it and then write it to the sql. I created a new column (nvarchar(150)) next to my current password column (so I could test logins) Also I shouldn’t have to say but do this in a test DB.

Using the code samples from Site 1 listed above lets first create an array or list of all current users with their passwords


sub getpasswords()
 Dim strSQL As String

 Dim sourceids As String = Nothing
 Dim conn1 As New SqlConnection("Your Server Connection")
 strSQL = "SELECT * FROM tblLogIn"
 conn1.Open()

 Dim newPass As New List(Of PasswordStruct)

 Dim kmd As New SqlCommand(strSQL, conn1)
 Dim r As SqlDataReader
 r = kmd.ExecuteReader()

'loop through table and add each user/password to a list
 If r.HasRows Then
 While r.Read()
 newPass.Add(New PasswordStruct(r("UserID"), r("USerName"), r("Password")))
 End While

 End If

 Dim PasswordCollection As ICollection = newPass
 For Each s As PasswordStruct In PasswordCollection

 'starts the function ComputeHash with password, userid, type of hash algorithm (choose one) and saltbytes
 ComputeHash(s.Password, s.UserID, "SHA256", Nothing)

 Next

 End sub

using the sample code for ComputeHash (see site #1 above), adding the argument for the userid and add this code to write each new hash to the DB


Dim strSQL As String
 'Dim conn As SqlConnection
 Dim sourceids As String = Nothing
 Dim conn1 As New SqlConnection("your sql connection")
 'update since records already exist
 strSQL = "UPDATE tblLogIn SET NewPassword=@computehash where userid =@userid

 Dim objkmd As New SqlCommand(strSQL, conn1)
 objkmd.CommandType = CommandType.Text
<pre>objkmd.Parameters.Add("@computehash", Convert.ToString(Request.QueryString("uCode")))
<pre> objkmd.Parameters.Add("@userid", Convert.ToString(Request.QueryString("UserId")))
 Try
 conn1.Open()
 objkmd.ExecuteNonQuery()
 Catch ex As Exception

 Finally

 objkmd.Dispose()
 conn1.Close()
 conn1.Dispose()
 End Try

You now have a column in your table with all the current users passwords hashed and salted.Forgotten Passwords

Forgotten, New and Changing Passwords

If your site is currently using plaintext passwords, odds are that when a user forgets their password, you are sending them their password in plaintext from the DB to their email address. Now since we’ve hashed and salted the new passwords, if you sent the user the long string of code in the DB, this wouldn’t help them login to the site. Our only option is to have the user change their password. We’ll email the user a link to the new password page, allow them to add a new password, from there we’ll do the same we did above, take the plaintext password and encrypt and salt it.

For this section we’ll be using the sample code on site #1 and site #2 above. Since you probably already have modules for the changing passwords or creating passwords for new users, I will not be adding code here, but telling you an outline of what you need to do.

Forgotten Passwords

Following the lead on example code site #2 , create your forgotten password page or add a panel on your current change password screen with the email fields and the password fields laid out on the website. Since the site doesn’t dive into if you have encrypted passwords, here is where you’ll need to make a change.

Using example code site #1, you’ll want to make a class for your own site, by making this code a class, you’ll be able to reuse the code not only for forgotten passwords but also for new user passwords and users changing their passwords.

Now once the user follows the long link provided in their email to change their password, they’ll input their new password and you’ll call ComputeHash with the arguments of  the plaintext password they supplied, the hashAlgorithm and saltbytes.

Fine, lets do it

Below is the code from Example site #2 with changes for computing the hash, be sure to update the code with your table and column names.


Protected Sub btnChangePwd_Click(sender As Object, e As System.EventArgs) Handles btnChangePwd.Click
Try
Dim thepwdhash as string

thepwdhash = SimpleHash.ComputeHash(txtNewPwd.Text.Text, "SHA256", Nothing) 'added code
' Here we will update the new password and also set the unique code to null so that it can be used only for once.
cmd = New SqlCommand("update Tbl_Login set UniqueCode='',Pwd=@pwd where UniqueCode=@uniqueCode and (EmailId=@emailid or UserName=@username)", con)
cmd.Parameters.AddWithValue("@uniqueCode", Convert.ToString(Request.QueryString("uCode")))
cmd.Parameters.AddWithValue("@emailid", Convert.ToString(Request.QueryString("emailId")))
cmd.Parameters.AddWithValue("@username", Convert.ToString(Request.QueryString("uName")))
cmd.Parameters.AddWithValue("@pwd", thepwdhash) ' changed pwd is the new hash instead of the plaintext that the user supplied
If con.State = ConnectionState.Closed Then
con.Open()
End If
cmd.ExecuteNonQuery()
lblStatus.Text = "Your password has been updated successfully."
txtNewPwd.Text = String.Empty
txtConfirmPwd.Text = String.Empty
Catch ex As Exception
lblStatus.Text = "Error Occured : " & ex.Message.ToString()
Finally
cmd.Dispose()
con.Close()
End Try
End Sub

The same can be done with your module for New User Password because there isn’t a password and you’re writing a new one, like above where we don’t care what the password was, we’re just writing a new one. It changes a bit for Changing Passwords.

Changing Passwords

When changing passwords, the difference is, we want to check the “old” password before we change the new password. You’ve probably already have code with textboxes that have one box for old password, 2 boxes for new password and a submit button.

Once the submit button is pressed we need to check the old password first. IF the old password matches, we can then once again compute the hash and write it over the old password


Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnSubmit.Click
If Page.IsValid Then
'check old password
Dim OldPassTrue As String
OldPassTrue = CheckOldPassword(PSW.Text)
If OldPassTrue = "True" Then

ComputeHash(PSW1.Text, lblEmail.Text, "SHA256", Nothing)
'then write the new password to the password column
Else
lblUserMessages.Text = "<br>Your old password does not match."
lblUserMessages.Visible = "true"
End If
End If
End Sub

Function CheckOldPassword(ByVal OldPass As String) As Boolean

Dim strSQL As String
Dim objConn As SqlConnection
Dim objkmd As SqlCommand
Dim OldPassGood As String = Nothing

strSQL = "SELECT NewPassword FROM tblLogin"
strSQL += " WHERE UserName = '" & username & "'"

objConn = New SqlConnection(ConfigurationManager.AppSettings("conn"))

objkmd = New SqlCommand(strSQL, objConn)
objkmd.CommandType = CommandType.Text
Try
objkmd.Connection.Open()
Dim dr As SqlDataReader = objkmd.ExecuteReader(CommandBehavior.CloseConnection)
If dr.HasRows() Then
dr.Read()

Dim passwordHashSha256 As String = dr("NewPassword")
OldPassGood = VerifyHash(OldPass, "SHA256", passwordHashSha256).ToString()

End If
dr.Close()

Catch ex As Exception
Response.Write(ex.ToString())
Finally
objkmd.Connection.Close()
objkmd.Dispose()
End Try
return OldPassGood
End Function

 

User Login

Last on our list of TODOs, users need to be able to login. If you’re currently using plaintext passwords, you’re just checking against the DB is the username and password match. We now need to (again) compute the hash for what the say is the password and then compare it against what’s in the DB, if the hashes match they the user is allowed in the site. You notice that we never decrypt the hash but just compare.

I added to my existing login code, after the user hit submit to login to the site


Dim DoesPasswordPass As Boolean

DoesPasswordPass = checkpassword(pass, user) 'if DoesPasswordPass = "True" then the user is allowed in the site

 


Public Shared Function checkpassword(ByVal password As String, ByVal user As String)

 Dim passwordHashSha256 As String
 Dim strSQL As String
 Dim PasswordPass As Boolean
 Dim sourceids As String = Nothing
 Dim conn1 As New SqlConnection(ConfigurationManager.AppSettings("readconn")) 'readonly

 strSQL = "SELECT NewPassword FROM tbllogin where userName= @userName"

 conn1.Open()

 Dim kmd As New SqlCommand(strSQL, conn1)

 kmd.Parameters.Add("@UserName", SqlDbType.VarChar, 50).Value = user
 passwordHashSha256 = kmd.ExecuteScalar().ToString()

 conn1.Dispose()
 kmd.Dispose()

 PasswordPass = VerifyHash(password, user, "SHA256", passwordHashSha256).ToString()</pre>
'password is what the user thinks is their password, SHA256 is hash type,  Return PasswordPass is
what the current hash is

 Return PasswordPass

 End Function

 

 

 

 

 

 

Technorati Tags: , , , , , ,

     

Can’t use TextBoxWatermarkExtender on Password Textbox in ASP.NET

On my new site I wanted to have the “fancy” text in the textbox that would clear once someone clicks in the box to start typing.

textboxwatermark

In ASP.NET there’s a nice AJAX extender called TextBoxWatermarkExtender that allows for this to happen, except if you set your textbox to type “password”, what ever work you add to the watermark shows as ********.

Thanks to this link: Display WaterMark text for Password TextBox in ASP.Net. I had my username and password up and showing in no time.

     

System.Web.Mail The classes in this namespace have been deprecated

Switching from system.web.mail to System.Net.Mail is pretty easy and straight forward, the syntax is a little different and instead of having the server declared in the class you declare it in the web.config.

Old System.Web.Mail version

Function SendEmail(ByVal strEmailTo As String, ByVal strEmailFrom As String, ByVal strSubject As String, ByVal strBody As String, ByVal strBodyFormat As String) As Boolean
        Dim email As New System.Web.Mail.MailMessage
        Dim bSent As Boolean = False
        If Trim(strEmailTo) <> "" Then
            email.To = strEmailTo
            email.From = strEmailFrom
            email.Body = strBody
            email.Subject = strSubject
            If UCase(strBodyFormat) = "TEXT" Then
                email.BodyFormat = Web.Mail.MailFormat.Text
            Else
                email.BodyFormat = Web.Mail.MailFormat.Html
            End If
            System.Web.Mail.SmtpMail.SmtpServer = "smtp.yourdomain.com"
			Try
				System.Web.Mail.SmtpMail.Send(email)
				bSent = True
			Catch ex As Exception
				bSent = False
			End Try
		End If
		SendEmail = bSent
    End Function

New System.net.Mail Version

 Function SendEmail(ByVal strEmailTo As String, ByVal strEmailFrom As String, ByVal strSubject As String, ByVal strBody As String, ByVal strBodyFormat As String) As Boolean
        Dim email As New MailMessage()
        Dim bSent As Boolean = False
        If Trim(strEmailTo) <> "" Then
            email.To.Add(New MailAddress(strEmailTo))
            email.From = New MailAddress(strEmailFrom)
            email.Body = strBody
            email.Subject = strSubject
            If UCase(strBodyFormat) = "TEXT" Then
                email.IsBodyHtml = "false"
            Else
                email.IsBodyHtml = "true"
            End If
            
            Try
                'System.Web.Mail.SmtpMail.Send(email)
                Dim mSmtpClient As New SmtpClient()
                ' Send the mail message
                mSmtpClient.Send(email)
                bSent = True
            Catch ex As Exception
                bSent = False
            End Try
        End If
        SendEmail = bSent
    End Function

Add the server to the web.config

<configuration>
   <system.net>
      <mailSettings>
         <smtp from="defaultEmail@yourdomain.com">
            <network host="smtp.yourdomain.com" port="25" userName="yourUserName" password="yourPassword"/>
         </smtp>
      </mailSettings>
   </system.net>
</configuration>

source

     

Creating an Unordered List for a MultiLevel Menu in Code Behind vb.net

As mentioned in New Series: Completely Redoing the Company Website, I’m creating our members website from scratch. One of the items on my to do list is the menu, since I’ll be using master pages, the menu will be placed on every page and will be a big part of the website.

Since our website is a members site, we have different security levels, depending on what your security level is, this will determin what links you get in the menus. (example: admins get links to admin pages). So our menu needed to be created on the fly depending on what the person logged in has as a security level.

Looking at the many ways to create a menu, the one’s I like are purly CSS based. With the CSS based menus you use an unordered (bulleted) list and then use CSS to create the menu as seen at Create a Multilevel Dropdown Menu with CSS

The Code Behind

Being that we already have a website, we already have the menu structure in our SQL database.
While your SQL structure will be different, you can get a hint on how to pull each sub to create your UL. (tables and column names changed to protect the innocent)

Grabbing the Main Menu Level


Sub GetMenuMain()

        
        SecurityLevel = getUserLevel.ReturnLevel
        Dim extraline As String
        Dim menuText As String
        Dim SubMenuList As New ArrayList()
        Dim ds As New DataSet()
        Dim cn As SqlConnection = New SqlConnection(ConfigurationManager.AppSettings("yoursqlconn"))
        Dim cmd As New SqlCommand("SELECT * FROM tblMainMenu where SecLvl <=" & SecurityLevel & " order by Seq", cn)
        Dim da As New SqlDataAdapter(cmd)
        da.Fill(ds)
        Dim table As DataTable = ds.Tables(0)
        


        Dim sb = New StringBuilder()
        If table.Rows.Count > 0 Then
            ' build the unordered list
            sb.AppendLine("<ul id='nav'>")
            For Each dr As DataRow In table.Rows
				' If this Menu Item has a sub menu
                If dr("SubMenuIDs").ToString() <> "*NONE" Then
                    SubMenuList.Add(dr("SubMenuIDs").ToString())
                    dr("SubMenuIDs").ToString() & "' data-dir='h' data-offsets='-10,5'>")
                    sb.AppendLine("<li class='mainmenu'><a href='" & dr("Pageurl").ToString() & "'>" & dr("itemName").ToString() & "</a>")
                    SubMenu = SubMenu & sb.ToString()
                    sb = New StringBuilder()
					' Go get the submenu
                    GetMenuSub(dr("SubMenuIDs").ToString())
                Else
					sb.AppendLine("<li class='mainmenu'><a href='" & dr("Pageurl").ToString() & "'>" & dr("itemName").ToString() & "</a></li>")

                End If
    
            Next
        End If
        sb.AppendLine("</ul>")
        
        SubMenu = SubMenu & sb.ToString()
        

    End Sub

Grabbing the Sub Menu Level

Sub GetMenuSub(ByVal submenuid As String)

        
        Dim ds As New DataSet()
        Dim cn As SqlConnection = New SqlConnection(ConfigurationManager.AppSettings("yoursqlconn"))
        Dim cmd As New SqlCommand("SELECT * FROM tblMenusSub where SubMenuIDs = '" & submenuid & "' AND SecLvl <=" & SecurityLevel & "", cn)
        Dim da As New SqlDataAdapter(cmd)
        da.Fill(ds)
        Dim table As DataTable = ds.Tables(0)
		Dim sb = New StringBuilder()
        If table.Rows.Count > 0 Then
			' build sub unordered list
            sb.AppendLine("<ul>")
            For Each dr As DataRow In table.Rows
                

                Dim TestPos As Integer
				'if submenu item starts with > then there is a subsub menu
                TestPos = InStr(1, dr("SubMenuText").ToString(), ">")
                If TestPos > 0 Then
                    Dim MyChar() As Char = {">"}
                    Dim NewString As String = dr("SubMenuText").ToString().TrimStart(MyChar)
                    'get subsubmenu loop here
                    sb.AppendLine("<li><a href='" & Trim(dr("HyperLink").ToString()) & "'>" & NewString & "&nbsp;&nbsp;&nbsp;<img src='/images/arrow.gif' border='0'></a>")
                    SubMenu = SubMenu & sb.ToString()
                    sb = New StringBuilder()
					'get subsub menu
                    GetSubSubMenus(Trim(dr("HyperLink").ToString()))

                Else
                    sb.AppendLine("<li><a href='" & Trim(dr("HyperLink").ToString()) & "'>" & dr("SubMenuText").ToString() & "</a></li>")

                End If
                
            Next
            sb.AppendLine("</ul></li>")
        End If
        SubMenu = SubMenu & sb.ToString()
        

    End Sub

Grabbing the SubSub Menu Level


Sub GetSubSubMenus(ByVal hyperlink As String)
        Dim ds As New DataSet()
        Dim cn As SqlConnection = New SqlConnection(ConfigurationManager.AppSettings("yoursqlconn"))
        Dim cmd As New SqlCommand("SELECT * FROM tblMenusSub where SubMenuIDs = '" & hyperlink & "' AND SecLvl <=" & SecurityLevel & " ORDER BY SubMenuID", cn)
        Dim da As New SqlDataAdapter(cmd)
        da.Fill(ds)
        Dim table As DataTable = ds.Tables(0)

        Dim sb = New StringBuilder()
        If table.Rows.Count > 0 Then
            sb.AppendLine("<ul>")
            For Each dr As DataRow In table.Rows
                
                sb.AppendLine("<li><a href='" & Trim(dr("HyperLink").ToString()) & "'>" & dr("SubMenuText").ToString() & "</a></li>")

            Next
            sb.AppendLine("</ul></li>")
        End If
        SubMenu = SubMenu & sb.ToString()
    End Sub

Your List

<ul id="nav">
    <li><a href="#">1 HTML</a></li>
    <li><a href="#">2 CSS</a></li>
    <li><a href="#">3 Javascript</a>
        <ul>
            <li><a href="#">3.1 jQuery</a>
                <ul>
                    <li><a href="#">3.1.1 Download</a></li>
                    <li><a href="#">3.1.2 Tutorial</a></li>
                </ul>
            </li>
            <li><a href="#">3.2 Mootools</a></li>
            <li><a href="#">3.3 Prototype</a></li>
        </ul>
    </li>
</ul>

Now use Kriesi’s page and format the CSS for your completed menu.