Introduction
Constructing the URL to a page within your solution is typically a messy task. Wouldn't it be nice if you could just say something like:
Redirect(new PrintItemPage(item, itemFormat))
That, of course, will not work.
So, instead of some nice, clean, strongly typed solution like that, we see people embedding references like "~/Print/Printitem.aspx" all over their solution. And, if that page needs parameters, they may well use string concatenation to construct the URL, maybe something like:
string url = "~/Print/Printitem.aspx?id=" + item.Id + "&format=" + itemFormat;
The smarter developer will have realized that it's better to define the basic URL string in a single location in the solution, and will have a constant string for that:
public const string baseUrl = "~/Print/Printitem.aspx?id={0}&format={1}";
But typically, the parameters for that page are still added in a weakly typed manner to the URL, something like:
string url = string.Format(Printitem.baseUrl, item1.id, item2.format)
Background
Code such as that shown in the introduction has several issues:
- References to ~/Print/Printitem.aspx are often scattered throughout the solution, making it hard to move a page to a different folder or to rename it.
- The parameters for the page are weakly typed, allowing run-time errors when someone accidentally links to that page, passing the ID for a
Foo
instead of an Item
.
- It is hard to discover (using the IDE) what the various parameter combinations are that can be used when referring to a different page in the solution.
Using the code
The solution to these issues is to create a strongly-typed static method on each of your page classes that returns a fully formed URL for that page. If there is more than one way to call the page, then provide multiple such static methods on your page class.
public static string UrlToSelf(Item item, Itemformat itemFormat)
{
return string.Format("~/print/printitem.aspx?id={0}&format={1}",
item.id, itemFormat.ToString());
}
public static string UrlToSelf(Item item)
{
return UrlToSelf(item, ItemFormat.Default);
}
With these static methods in place, you can now discover (using the IDE) how to call the PrintItem
page. Intellisense will show you that there are two calls you can make and that you must pass in an Item
object.
It's now impossible for you to link or redirect over to the PrintItem
page passing it anything but the object type it expects.
Points of interest
Duplicate code is always a bad idea: it leads to code bloat; it causes bugs to appear in some places, but not others; bugs 'fixed' mysteriously reappear in other places because the developer didn't go find all copies of that code when he or she fixed a bug that had been found in one of them.
"One-fact, one-place" is a great mantra not just for database developers, everyone should aim for it. If you are ever tempted to use "cut-and-paste coding" because it's 'quicker', just remember that 2x the code will produce 2x as many bugs and will be 2x as hard to maintain. It is always better to avoid duplication and to spend time creating a reusable method that puts "one fact" in "one place". Every sprint cycle should include time for this kind of refactoring to ensure that your solution stays clean and maintainable.
Related article
See also ... another article on how to do the same for Web User Controls.
History
- July 2007, First version.