Mark Gilbert's Blog

Science and technology, served light and fluffy.

Going out without my Markup on – User Control Properties and System.Web.Routing

I heart System.Web.Routing.

Over the last few professional projects I’ve had, I’ve used Routing to create search-engine friendly URLs, dynamically generate product pages based on database records (a single Webform gets used for multiple different products), and dynamically generate 301 Redirects to provide a easy transition from an old site to a new one.

I heart System.Web.Routing.

Of course, any great relationship has its rough parts.  A few weeks ago, I hit one with Routing.  It seems Routing doesn’t like Webform user control properties all that much – at least the ones assigned in markup.

When I create a new route, one of the classes I need to create is a route “handler” which implements the IRouteHandler interface.  Here is a typical implementation:

Imports Microsoft.VisualBasic
Imports System.Web.Routing
Imports System.Security
Imports System.Web.Compilation

Public Class MyPageHandler
    Implements IRouteHandler

    Private _VirtualPath As String
    Private _MyCustomValue As Long

    Public Sub New(ByVal VirtualPath As String, ByVal MyCustomValue As Long)
        If (IsNothing(VirtualPath)) Then VirtualPath = ""
        Me._VirtualPath = VirtualPath
        Me._MyCustomValue = MyCustomValue
    End Sub

    Public Function GetHttpHandler(ByVal requestContext As System.Web.Routing.RequestContext) As System.Web.IHttpHandler Implements System.Web.Routing.IRouteHandler.GetHttpHandler
        Dim TestHandler As IHttpHandler
        Dim MyPageHandler As MyPage

        TestHandler = TryCast(BuildManager.CreateInstanceFromVirtualPath(Me._VirtualPath, GetType(IHttpHandler)), IHttpHandler)
        MyPageHandler = CType(TestHandler, MyPage)
        MyPageHandler.MyCustomProperty = Me._MyCustomValue

        Return MyPageHandler
    End Function
End Class

This class does the work of mapping the request to the underlying Webform, and passing any parameters through.

Now on the Webform itself I’ll have one or more user controls.  I find myself often creating custom properties on those controls so I can pass in data directly (as opposed to putting something in session or cache, and letting the control pull it out).  I will then typically set those properties in markup, either with a static value, or more frequently with an expression hole:

<uc1:Footer id=”Footer1″
runat
=”server”
MyCustomProperty=”<%=Me.MyCustomValue %>
“>

</uc1:Footer>

What I found with Routing, however, is that the custom properties can’t be assigned in markup.  If they are, an error occurs when the page is instantiated:

Cannot create an object of type ‘System.Int64’ from its string representation ‘<%=Me.MyCustomValue %>’ for the ‘MyCustomProperty’ property.

This error occurs on the TryCast statement in the GetHttpHandler function.  After a little tinkering I found that I could avoid this error by instead assigning the property’s value in the PreInit() event handler of the page:

Private Sub Page_PreInit(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreInit
    Footer1.MyCustomProperty = Me.MyCustomValue
End Sub

I haven’t found a reason why I can’t put assignments like this in markup, but I wonder if the Routing mechanism is simply trying to render the page before “Me.MyCustomValue” has been assigned a value, whereas doing it in the PreInit moves it sufficiently upstream so everything is happy.

Advertisements

May 8, 2010 - Posted by | Visual Studio/.NET

Sorry, the comment form is closed at this time.

%d bloggers like this: