After writing a very large web-based application with lots of pages, I realized that I was falling into a trap.
Magic strings were going to be the death of me!
If you are not familiar with what a "magic string" is, it is really any type of string in your application that is not strongly typed somehow. For example, if you write a paragraph like this:
lblParagraph.Text = "<p>This is a paragraph.";
you have a lot of string magic going on! You probably would want to refactor that to have a strongly typed object that implies you are dealing with a paragraph, and then refer to the text based on its source, whether it's a constant, resource, or another way to inject the information without making it magically reside in the code.
So, what is a common pattern in our website (this is addressed in MVC, by the way, I'm talking the old WebForms engine)?
This seems fine until you end up refactoring the page or splitting it up, etc. Isn't there a better way?
My first step was to start to use constants like this:
const string NAVIGATE_SOME_PAGE = "~/Some/Page.aspx";
This was a little more satisfying, until I realized that I was dotting my entire application with multiple "
NAVIGATE_SOME_PAGE" references. I could have hacked it by referencing them publicly, but was that really the right way?
Fortunately, our application follows strict naming conventions including adhering to proper namespace use. We don't create a folder called "foo" and then stick an entity in that folder into the namespace "bar".
So, I decided to come up with an extension method. Why an extension method? Because, I couldn't think of some dummy utility class to paste then on when it really is a function of the "Page" knowing where "it" is. So, I extended the page, and did this:
Note: this implies you inherit your pages from
BaseController .. you could just as easily make it
Now, when I want to redirect, I do this:
And, the best part? If I delete the page, my compiler throws errors. If I refactor the page, all of the redirects will get refactored with it.
(I realize hacking the namespace to make a path doesn't seem the most elegant solution, but it's the best I could come up with ... I'm very open to other ideas on how to tackle this).