Appending Text To The Titles Of All Web Pages

Have you ever wanted to add a text string, like an application name, to the title of all your web pages. It’s easy to do using the control adapters available in ASP.NET 2.0 and later. First, create a new .browser file in the App_Browsers folder of your application, or add this entry to an existing file. Be sure to substitute MyNamespace for the correct namespace where the class is located.

<browsers>

  <browser refID="Default">
    <controlAdapters>
      <adapter controlType="System.Web.UI.HtmlControls.HtmlHead"
               adapterType="MyNamespace.TitleAdapter" />
    </controlAdapters>
  </browser>

</browsers>

Now create the TitleAdapter class that is referenced by the .browser file:

Imports System.Web.UI.Adapters

Public Class TitleAdapter
    Inherits ControlAdapter

    Private Shared _titleAppendString As String = " - Your Application Name Here"
    Public Shared Property TitleAppendString() As String
        Get
            Return _titleAppendString
        End Get
        Set(ByVal value As String)
            _titleAppendString = value
        End Set
    End Property

    Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
        MyBase.Render(New TitleAdapterHtmlTextWriter(writer, TitleAppendString))
    End Sub

End Class

And finally, create the HtmlTextWriter that is referenced by the control adapter:

Public Class TitleAdapterHtmlTextWriter
    Inherits HtmlTextWriter

    Public Sub New(ByVal writer As HtmlTextWriter, ByVal appendString As String)
        MyBase.New(writer)
        InnerWriter = writer.InnerWriter

        _appendString = appendString
    End Sub

    Public Sub New(ByVal writer As System.IO.TextWriter, ByVal appendString As String)
        MyBase.New(writer)
        InnerWriter = writer

        _appendString = appendString
    End Sub

    Private _appendString As String

    Private _renderingTitle As Boolean = False
    Private _nestedCount As Integer

    Public Overrides Sub RenderBeginTag(ByVal tagName As String)
        If _renderingTitle Then
            _nestedCount += 1
        ElseIf String.Equals(tagName, "title", StringComparison.InvariantCultureIgnoreCase) Then
            _renderingTitle = True
            _nestedCount = 0
        End If

        MyBase.RenderBeginTag(tagName)
    End Sub

    Public Overrides Sub RenderBeginTag(ByVal tagKey As System.Web.UI.HtmlTextWriterTag)
        If _renderingTitle Then
            _nestedCount += 1
        ElseIf tagKey = HtmlTextWriterTag.Title Then
            _renderingTitle = True
            _nestedCount = 0
        End If

        MyBase.RenderBeginTag(tagKey)
    End Sub

    Public Overrides Sub RenderEndTag()
        If _renderingTitle Then
            If _nestedCount > 0 Then
                _nestedCount -= 1
            Else
                _renderingTitle = False
                Write(_appendString)
            End If
        End If

        MyBase.RenderEndTag()
    End Sub

End Class

Note that you can edit the text string in the TitleAdapter class. Additionally, it is a static variable so you can alter it at startup from a database column in your Global.asax file.

Using Enumerations For Columns With LINQ

One of the great features of LINQ that DataSets didn’t support well is the ability to use enumerations for your columns instead of integers. It can make writing and working with your code a lot easier. This is accomplished by manually setting the Type of the column to the type of the enumeration in the visual designer.

There are two important notes to remember about doing this. First, it takes extra work if you want to use an enumeration that is in a different namespace from the LINQ classes. You must not only include the full namespace, but also the global:: prefix. So “global::EnumNamespace.EnumTypeName” refers to the enumeration EnumTypeName in the EnumNamespace namespace. Secondly, if you want to update the data structure from the database, you have to remember to manually set the Type back to the enum type from integer.

This system works great most of the time, including when performing LINQ queries in your code. However, the one place it doesn’t seem to work well is in the Where clause of a LinqDataSource. If you try to select on the column values of an enumeration column here, you’ll get various exceptions. If you try to refer to the enumeration constants, you get “No property or field ‘x‘ exists in type ‘y‘. I’ve tried various namespace permutations with no success. If you try to use integers directly instead of enumeration members, you get “Argument types do not match”.

The only solution I have found to the problem is to typecast the column and compare to integers. For example, “Int32(ColumnName) == 1″. Personally, I don’t like this solution much because it can cause huge problems if your constants ever change, but it works.

Also, if you are dealing with a Flags enumeration, it gets even worse. I haven’t found any way to do bitwise operations in the Where clause, so you have to compare the column to all possible integers that contain the bits you are interested in.

If anybody knows of a better way to address this issue, please post a comment and let me know. Thanks.