Scott on Writing

Musings on technical writing...

Using a Base Class to Fiddle with a Page's Rendered Output

Imagine that you wanted to tweak a page's rendered output in some manner - perhaps inject a copyright notice at the bottom of the page or ensure that <link> tags to required stylesheets were present.  There are a number of options available to make this happen in ASP.NET.:

  1. The simplest (but least tenable) approach is to simply add the logic to each and every page that requires it.  This can be a maintainence nightmare, however, as if the logic changes you need to revisit every page that has this logic hard coded.  Similarly, adding new pages to the site that utilize this same logic requires copying and pasting code.
  2. A more centralized approach would be to tap into an application event, if available.  For example, this might be a good choice if you wanted to use some kind of special encryption or compression on the page's output.
  3. While the Global.asax approach is better than adding the logic to each individual page, it still has the problem of tightly coupling the logic with the application.  If you wanted to replicate the logic in another Web application, for instance, you'd need to replicate the code.  This takes us back to our initial problem - what happens if the logic needs to change or be updated?  What happens when we want to add another Web application that uses this logic?  We'd need to replicate the Global.asax code in each of these applications.  Boo.

    A better, more losely coupled approach is to use an HTTP Module.  It has access to the same application-level events, and can be packaged up as a stand-alone assembly that can be added or removed to Web applications as easily as you can add or remove a file from a directory.  No recompilation/redeployment needed.  (See Using HTTP Modules and Handlers to Create Pluggable ASP.NET Components for more info on using an HTTP Modules in this manner, along with an examination of a global error logging component, ELMAH.)
  4. A final approach is to use a base class that the ASP.NET pages in your application extend.  The logic necessary can be placed in this base class.  This technique is used in DotNetNuke (well, it was in version 2.x, I haven't poked around version 3 yet).  DotNetNuke uses a base class to move the __VIEWSTATE hidden form field to the bottom of the <form> so as not to gunk up search engines or Google AdSense.  Here's the base class, some code has been removed for brevity:

Public Class BasePage
  Inherits System.Web.UI.Page

  '
  ' This method overrides the Render() method for the page and moves the ViewState
  ' from its default location at the top of the page to the bottom of the page. This
  ' results in better search engine spidering.
  '
  Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
      Dim stringWriter As System.IO.StringWriter = New System.IO.StringWriter
      Dim htmlWriter As HtmlTextWriter = New HtmlTextWriter(stringWriter)
      MyBase.Render(htmlWriter)
      Dim html As String = stringWriter.ToString()
      Dim StartPoint As Integer = html.IndexOf("<input type=""hidden"" name=""__VIEWSTATE""")
      If StartPoint >= 0 Then 'does __VIEWSTATE exist?
          Dim EndPoint As Integer = html.IndexOf("/>", StartPoint) + 2
          Dim ViewStateInput As String = html.Substring(StartPoint, EndPoint - StartPoint)
          html = html.Remove(StartPoint, EndPoint - StartPoint)
          Dim FormEndStart As Integer = html.IndexOf("</form>") - 1
          If FormEndStart >= 0 Then
              html = html.Insert(FormEndStart, ViewStateInput)
          End If
      End If
      writer.Write(html)
  End Sub
End Class 'BasePage

For more information check out the DotNetNuke source or my latest 4Guys article, Using a Custom Base Class for your ASP.NET Page's Code-Behind Classes.

posted on Thursday, April 14, 2005 3:02 PM

Feedback

# re: Using a Base Class to Fiddle with a Page's Rendered Output 4/15/2005 2:46 AM Darren Neimke

That's interesting... I thought that you had to use Filters if you wanted to tamper with the output in a manner such as that.

# re: Using a Base Class to Fiddle with a Page's Rendered Output 4/16/2005 8:52 PM Rick Strahl

On a related note, I posted a few approaches to capturing ASP.NET output in a number of ways here, which also implicitly lets you fiddle with the output:

http://west-wind.com/weblog/posts/481.aspx

# re: Using a Base Class to Fiddle with a Page's Rendered Output 4/21/2005 8:32 AM lizardsis

I have problem with option 4. The page that inherits PageBase contains Web User Control with Response.Write code blocks embedded inside its html like:
<img src='<% Response.Write(myPage.Config.Constants.SiteRoot) %>/images/logo.jpg'>. It seems that the result of Response.Write is rendered before the output of Protected Overrides Sub Render(that is html). I would be grateful for any suggestions.

# re: Using a Base Class to Fiddle with a Page's Rendered Output 5/1/2005 12:50 PM Erik Porter

Sorry I'm so late on this, but I just wanted to say...

This is a great tip. I do it all the time for things like, changing the title of the page (i.e. adding more to it), allowing non-server controls to use the "~", changing the body tag, etc

# re: Using a Base Class to Fiddle with a Page's Rendered Output 6/2/2005 3:24 PM Matt

For the C# programmers out there, 'MyBase' is apparently the VB.NET equivalent of C#'s 'base'

(Why did they name it 'MyBase' instead of just 'Base' or 'base'? I thought the MS habit of prefixing variable names with 'My' was just for code examples. It must have something to do with VB's lack of case-sensitivity, but that's no excuse for such a lame name. Even AllYourBase would be cooler than MyBase!)

# re: Using a Base Class to Fiddle with a Page's Rendered Output 12/8/2005 11:49 AM slolife

This code:

Dim FormEndStart As Integer = html.IndexOf("</form>") - 1
If FormEndStart >= 0 Then
html = html.Insert(FormEndStart, ViewStateInput)
End If

creates a problem when a control butts itself up against the ending form tag (</form>). You should remove the -1 and things work well.

I have a page that produces this:

</script></form>

and the -1 in the line above inserts the viewstate like this:

</script<input... />></form>

# Viewstate-Optimization for ASP.NET 5/14/2008 3:20 AM ASP.NET SEO Blog

Viewstate-Optimization for ASP.NET

Title:  
Name:  
Url:
Protected by Clearscreen.SharpHIPEnter the code you see:
Comments   

Add To Your Reader

My Links

Archives

Post Categories

 

I am a Microsoft MVP for ASP.NET.
I am an ASPInsider.
<May 2008>
SMTWTFS
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

Comment Stats

DayTotal% of Total
Sunday 1866.8%
Monday 37913.9%
Tuesday 45316.7%
Wednesday 50418.5%
Thursday 53519.7%
Friday 49418.2%
Saturday 1666.1%
Total 2717100.0%

Hour1Total% of Total
12:00 AM 652.4%
1:00 AM 682.5%
2:00 AM 622.3%
3:00 AM 742.7%
4:00 AM 572.1%
5:00 AM 1033.8%
6:00 AM 1084.0%
7:00 AM 1585.8%
8:00 AM 1716.3%
9:00 AM 1475.4%
10:00 AM 1716.3%
11:00 AM 1816.7%
12:00 PM 1886.9%
1:00 PM 1696.2%
2:00 PM 1605.9%
3:00 PM 1324.9%
4:00 PM 1073.9%
5:00 PM 923.4%
6:00 PM 913.3%
7:00 PM 963.5%
8:00 PM 833.1%
9:00 PM 782.9%
10:00 PM 792.9%
11:00 PM 772.8%
Total 2717100.0%

Comments by Blog Entry Date/Time

Day Entry MadeAvg.Total
Sunday 5.54144
Monday 5.22339
Tuesday 4.28419
Wednesday 7.67637
Thursday 6.90607
Friday 5.48411
Saturday 5.33160
Total 5.842717

Hour1 Entry MadeAvg.Total
12:00 AM 5.0035
1:00 AM 1.002
5:00 AM 0.000
7:00 AM 7.0035
8:00 AM 5.35107
9:00 AM 6.32278
10:00 AM 6.47246
11:00 AM 4.41181
12:00 PM 6.88330
1:00 PM 3.00111
2:00 PM 5.41222
3:00 PM 8.64285
4:00 PM 4.0589
5:00 PM 5.92154
6:00 PM 4.52113
7:00 PM 9.67174
8:00 PM 9.80147
9:00 PM 5.05111
10:00 PM 5.4265
11:00 PM 4.5732
Total 5.842717

Learn More About Comment Stats
1 - All times GMT -8...


Blog Stats

Favorite Web Sites

My Books

My MSDN Articles