Getting a page's URL in code-behind

You may have the need to be able to get the URL to a page in a web application from the server code. This might be because the page could move or because the URL is dynamic in some way. While this would be a nice feature to have in .NET, there are reasons it is not. We'll discuss this and a simple solution for getting a page's URL in server-side code that saves us from hard coding it in the referencing pages.

While it would be a very nice feature to have in .NET it seems to make sense that there is no method that will generate a URL for you to a page even though we have strongly typed code-behind classes that often times drive the page. Consider that the pages are just ASPX files that can be named anything and can live anywhere in your application structure. They can be derived from any page-derived class in the accessible namespaces (the framework supplied System.Web.UI.Page class, or any class that you create in your application assemblies that was derived from the framework's web page class). This provides us with very flexible design and application structure but as a result we don't have a reliable way to say "give me the URL for X". A solution to this that solves two problems at once is to create a shared/static GetUrl() method on the pages. This method provides the root-relative URL to the page that owns the code-behind class as well as specifying required parameters so you don't have to guess at them or encounter problems later on. Let's take an example of a class that shows the attributes for some item. This page lives at the root of our application: ourApplication/ItemAttributes.aspx Here's the code-behind class:

Public Class ItemAttributes
  Inherits System.Web.UI.Page
  Public Shared Function GetUrl(itemID As Integer, _
    page As System.Web.UI.Page) As String
     Return page.ResolveUrl("~/ItemAttributes.aspx?itemID=" _
       & itemID.ToString)
  End Function
End Class

The GetUrl() method expects a couple of arguments: first an itemID because we need a reference to some item so we know what item's attributes to show; second, an instance of a System.Web.UI.Page class. We need the instance of the page class so we can access the Page.ResolveUrl() method. Now, any other pages in the application can create links to this page by calling the public shared method:

ItemAttributes.GetUrl(12, Me)
  'returns "/ourApplication/ItemAttributes.aspx?itemID=12"

A benefit of this technique is that we get a more robust application that is not quite as suceptible to growing pains. Let's say that we move this page because our application is getting bigger and the pages are getting cluttered. We'll move the page to a directory of common pages: ourApplication/common/ItemAttributes.aspx We can just modify the returned string in the GetUrl() method. All the pages that call GetUrl() to use this page link will follow along without a glitch:

Public Shared Function GetUrl(itemID As Integer, _
   page As System.Web.UI.Page) As String
Return page.ResolveUrl("~/common/ItemAttributes.aspx?itemID=" _
     & itemID.ToString)
	End Function

Now let's imagine that we have to add another querystring value to the page because we now need to get information about the category that this item is in. When we modify our page to look for the querystring value all the page requests (from other pages) will start failing. We don't know all the places that this page is called in the application so we will have to do some search and replacing as well as a pretty good job testing the application to find the now-broken references. However, there is salvation! All we have to do is change the GetUrl() method signature to expect the new argument and change the returned string structure:

Public Shared Function GetUrl(itemID As Integer, categoryID As Integer, _
   page As System.Web.UI.Page) As String
   Return page.ResolveUrl("~/common/ItemAttributes.aspx?itemID=" _
     & itemID.ToString & "&categoryID=" & categoryID.ToString)
End Function

Now when we try to the build the application we'll get compile errors everywhere that this method is called. We can go and repair all those broken calls with the confidence. Of course, depending on how you build your pages, you could add an overloaded method that still accepts the original set of arguments and have it call the new method with a default value so you don't have to repair broken calls. This is a great approach if you can build the changed page to function without the additional information. By using this technique you get several advantages: 1. Flexibility to move pages without having to change lots of hard-coded URLs. 2. Compile-time debugging (reduces testing and potential customer discoveries of overlooked runtime bugs) 3. Multi-developer teams don't have to waste precious time researching what the page expects for a querystring because the calls have strongly typed arguments with descriptive names.

Where to Next?

Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article.

Doc ID 371
Full URL
Short cut
Written by Imar Spaanjaars
Date Posted 08/06/2005 22:24

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the Doc ID of the document.

(Plain text only; no HTML or code that looks like HTML or XML. In other words, don't use < and >. Also no links allowed.