Monthly Archives: February 2011

Creating dynamic meta tags using ASP .NET

SEO (search engine optimization) is all the rage these days. There are many great sites on the web that nobody’s ever seen or heard of. Part of the reason might be that the sites haven’t been optimized for search engines. I’ll do another post all about SEO some day, but for right now I want to highlight a couple of ways that you can enhance the pages on your site.

All good ASP .NET sites have a sitemap that organizes the site. If you don’t have a CMS (content management system), this is also a great place to store meta information about each page, such as the description and key words. These can be added as attributes on the sitemap, along with any other possible meta tags. I created a user control that I like to use that handles meta tags, and I just drop this into the master pages on the sites that I create. As long as I have a solid sitemap, the control takes care of the rest. I also like to take care of the page title for each page in this control, it’s handled in the code behind.

As you can see in the following sitemap file, I’ve used the description attribute, and also added my own keyWords attribute. Although key words aren’t as popular as they used to be for SEO, I like to go ahead and add them if I have a few handy. If you don’t list any key words, the control just ignores that attribute.




  
    
      
      
      
    
  

Here is the markup for the control, looks very straightforward, doesn’t it? Notice that the visibility on all the controls is initially set to false, because not all pages are going to have all of these attributes.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MetaTags.ascx.cs" Inherits="usercontrols_MetaTags" %>






Then in the code behind, I look at the attributes on the current sitemapnode and determine which tags to enable. This control is best used in conjunction with a master page, so that you only need to add this once, and any page using the master page will automatically be taken care of. Also notice that we use the title attribute on the sitemap to set the page title. I store a site name in the configuration that I prepend to each title. Not sure if that’s a best practice these days, just a preference of mine.

    protected void Page_Load(object sender, EventArgs e)
    {
        //First, check to see that we even need to handle this page, pages not in the sitemap will not have meta tags
        if (System.Web.SiteMap.CurrentNode != null)
        {
            this.Page.Title = ConfigurationManager.AppSettings["SiteName"] + " - " + System.Web.SiteMap.CurrentNode.Title;
            if (System.Web.SiteMap.CurrentNode.Description != null && !string.IsNullOrEmpty(System.Web.SiteMap.CurrentNode.Description))
            {
                metaDescription.Visible = true;
                metaDescription.Attributes.Add("content", System.Web.SiteMap.CurrentNode.Description);
            }

            if (System.Web.SiteMap.CurrentNode["keyWords"] != null && !string.IsNullOrEmpty(System.Web.SiteMap.CurrentNode["keyWords"]))
            {
                metaKeywords.Visible = true;
                metaKeywords.Attributes.Add("content", System.Web.SiteMap.CurrentNode["keyWords"]);
            }

            if (System.Web.SiteMap.CurrentNode["robots"] != null && !string.IsNullOrEmpty(System.Web.SiteMap.CurrentNode["robots"]))
            {
                metaRobots.Visible = true;
                metaRobots.Attributes.Add("content", System.Web.SiteMap.CurrentNode["robots"]);
            }

            if (System.Web.SiteMap.CurrentNode["author"] != null && !string.IsNullOrEmpty(System.Web.SiteMap.CurrentNode["author"]))
            {
                metaAuthor.Visible = true;
                metaAuthor.Attributes.Add("content", System.Web.SiteMap.CurrentNode["author"]);
            }

            if (System.Web.SiteMap.CurrentNode["copyright"] != null && !string.IsNullOrEmpty(System.Web.SiteMap.CurrentNode["copyright"]))
            {
                metaCopyright.Visible = true;
                metaCopyright.Attributes.Add("content", System.Web.SiteMap.CurrentNode["copyright"]);
            }
        }
        else
        {
            //At the very least, set a default page title
            this.Page.Title = ConfigurationManager.AppSettings["SiteName"];
        }
    }

Although I rarely use, or never use, a couple of those meta tags, I like to have them there just in case. The result of using this control in conjunction with the sitemap is something that looks like the following in the head section your rendered page source:


    
    

WordPress is suppressing the title tag, but just imagine the following in the code snippet above <title>My Site name – Home Page</title>

Building a dynamic navigation menu in ASP .NET

ASP .NET provides a few out of the box controls for navigation, but for most people, a custom navigation menu is the way to go. A common pattern that I use is creating a series of unordered lists to represent my navigation, and then I’ll use some kind of javascript to make it a little more flashy. Given the sitemap below, we’ll generate the markup needed to create a menu similar to what can be found here: Sample Menu



  
    
      
      
      
    
    
      
      
    
    
      
      
      
    
  

The markup that we’re after looks something like this:

  • Main Navigation 1
    • Sub Navigation 1
    • Sub Navigation 2
    • Sub Navigation 3
  • Main Navigation 2
    • Sub Navigation 4
    • Sub Navigation 5
  • Main Navigation 3
    • Sub Navigation 6
    • Sub Navigation 7
    • Sub Navigation 8

We can use a combination of the Sitemap objects and ASP .NET repeaters to get the desired result. If you haven’t already done so, first you must configure your site to use the sitemap. By default, your site will look for a file called Web.sitemap, or you can manually configure the sitemap in the Web.config file.

I like to put all of the code for generating the navigation inside of a user control. It always seems to make piecing together a page a little easier, and if I need to do multiple master pages, I can reuse the navigation code if needed. In order to get the markup in the right structure, I nest a repeater within another repeater:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="top-navigation.ascx.cs" Inherits="uc_top_navigation" %>

Notice that I added an OnItemDataBound handler to the main repeater. I do this so that during each iteration of the repeater, I can bind the nested repeater to the sitemap.

In the page load event of the user control, I need to bind my sitemap to the first repeater. Because of the way I’ve structured my sitemap, I want the nodes that are just below the root node. I set the source of my repeater to be these nodes, and then bind it. This gets me the top bar of my navigation, but no dropdowns just yet.

    protected void Page_Load(object sender, EventArgs e)
    {
        navBar.DataSource = System.Web.SiteMap.RootNode.ChildNodes;
        navBar.DataBind();
    }

Now that I have my top bar going across the top, it’s time to add the dropdown menus. Using the OnItemDataBound handler on the first repeater, we can get an instance of the current node that we’re working with, and use those child nodes to build out the markup for the menu. The code for this might look like this:


    protected void navBar_OnItemDataBound(object sender, RepeaterItemEventArgs e)
    {
        SiteMapNode currentRepeaterNode = (SiteMapNode)e.Item.DataItem;
        ((Repeater)e.Item.FindControl("subNavDropdown")).DataSource = currentRepeaterNode.ChildNodes;
        ((Repeater)e.Item.FindControl("subNavDropdown")).DataBind();
    }

This gives us the markup that we need. Paired with a proper javascript file and css, this is a simple pattern to follow for creating a dynamic navigation menu.