Background: I have to append to query string values from the initial call to the website, unique for each user, to every internal link on every subsequent page call for the rest of their visit to the site to preserve tracking information for Google Analytics. I store these values in the Session object in the Global.asax during Session_Start. I've made a custom Page object that overrides CreateHtmlTextWriter to supply a custom HtmlTextWriter object that has overriden all the public AddAttribute and WriteAttribute methods that check the name/key to see if it is "href" and if so, append the additional Query String parameters to the value object during the Render process. This works for links that were generated via an ASP.NET control, i.e. Hyperlink like:
<asp:HyperLink BackColor="Red" ID="link" runat="server" NavigateUrl="http://www.google.com/" Text="Google" />
but doesn't work if a just wrote:
<a href="http://www.yahoo.com/">Yahoo</a>
directly in the aspx page. What part of HtmlTextWriter does HTML from the aspx page render through?
I'm including my code files for the proof of concept I'm trying to get working (doesn't try to idenitfy whether the link is internal or external, that will be for later)[This is built using Webforms, .NET Framework 3.5 and C#]:
Default.aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TestRenderOverride._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:HyperLink BackColor="Red" ID="link" runat="server" NavigateUrl="http://www.google.com/" Text="Google" />
<br />
<a href="http://www.yahoo.com/">Yahoo</a>
</div>
</form>
</body>
</html>
Default.aspx.cs (includes both the custom Page class and the custom HtmlTextWriter class):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
namespace TestRenderOverride
{
public partial class _Default : CustomPage
{
protected void Page_Load(object sender, EventArgs e)
{
HyperLink hl = new HyperLink();
}
}
public class CustomPage : System.Web.UI.Page
{
protected override HtmlTextWriter CreateHtmlTextWriter(TextWriter tw)
{
return new CustomHtmlTextWriter(HttpContext.Current, tw);
}
}
public class CustomHtmlTextWriter : HtmlTextWriter
{
private string UTM_A;
private string UTM_B;
public CustomHtmlTextWriter(HttpContext context, TextWriter writer) : base(writer)
{
if (context.Session["Protected_UTM-A"] != null)
{
UTM_A = context.Session["Protected_UTM-A"].ToString();
}
if (context.Session["Protected_UTM-B"] != null)
{
UTM_B = context.Session["Protected_UTM-B"].ToString();
}
}
public CustomHtmlTextWriter(HttpRequest request, TextWriter writer, string tabString)
: base(writer, tabString)
{
}
private string AppendCustomQueryString(string value)
{
if (HasQueryStringValues())
{
if (value.Contains('?'))
{
return value + "&" + BuildQueryStringAddition();
}
else
{
return value + "?" + BuildQueryStringAddition();
}
}
else
{
return value;
}
}
private string BuildQueryStringAddition()
{
string returnValue = String.Empty;
if (!String.IsNullOrEmpty(UTM_A))
{
returnValue = "UTM_A=" + UTM_A;
}
if (!String.IsNullOrEmpty(UTM_B))
{
if (!String.IsNullOrEmpty(returnValue))
{
returnValue += "&UTM_B=" + UTM_B;
}
else
{
returnValue = "UTM_B=" + UTM_B;
}
}
return returnValue;
}
private bool HasQueryStringValues()
{
if (!String.IsNullOrEmpty(UTM_A) || !String.IsNullOrEmpty(UTM_B))
{
return true;
}
return false;
}
public override void AddAttribute(HtmlTextWriterAttribute key, string value)
{
if (key == HtmlTextWriterAttribute.Href)
{
value = AppendCustomQueryString(value);
}
base.AddAttribute(key, value);
}
public override void AddAttribute(string name, string value)
{
if (name.ToLowerInvariant() == "href")
{
value = AppendCustomQueryString(value);
}
base.AddAttribute(name, value);
}
public override void AddAttribute(HtmlTextWriterAttribute key, string value, bool fEncode)
{
if (key == HtmlTextWriterAttribute.Href)
{
value = AppendCustomQueryString(value);
}
base.AddAttribute(key, value, fEncode);
}
public override void AddAttribute(string name, string value, bool fEndode)
{
if (name.ToLowerInvariant() == "href")
{
value = AppendCustomQueryString(value);
}
base.AddAttribute(name, value, fEndode);
}
protected override void AddAttribute(string name, string value, HtmlTextWriterAttribute key)
{
if ((name.ToLowerInvariant() == "href") || (key == HtmlTextWriterAttribute.Href))
{
value = AppendCustomQueryString(value);
}
base.AddAttribute(name, value, key);
}
public override void WriteAttribute(string name, string value)
{
if (name.ToLowerInvariant() == "href")
{
value = AppendCustomQueryString(value);
}
base.WriteAttribute(name, value);
}
public override void WriteAttribute(string name, string value, bool fEncode)
{
if (name.ToLowerInvariant() == "href")
{
value = AppendCustomQueryString(value);
}
base.WriteAttribute(name, value, fEncode);
}
public override void WriteStyleAttribute(string name, string value)
{
if (name.ToLowerInvariant() == "href")
{
value = AppendCustomQueryString(value);
}
base.WriteAttribute(name, value);
}
public override void WriteStyleAttribute(string name, string value, bool fEncode)
{
if (name.ToLowerInvariant() == "href")
{
value = AppendCustomQueryString(value);
}
base.WriteAttribute(name, value, fEncode);
}
}
}
Global.asax:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
namespace TestRenderOverride
{
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
}
protected void Session_Start(object sender, EventArgs e)
{
if (Request.QueryString["UTM_A"] != null)
{
Session["Protected_UTM-A"] = Request.QueryString["UTM_A"].ToString();
}
if (Request.QueryString["UTM_B"] != null)
{
Session["Protected_UTM-B"] = Request.QueryString["UTM_B"].ToString();
}
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
}
protected void Application_Error(object sender, EventArgs e)
{
}
protected void Session_End(object sender, EventArgs e)
{
}
protected void Application_End(object sender, EventArgs e)
{
}
}
}
Here is the source that is rendered when you run the code and set Start Page of the web project to "Specific Page" with the value of "Default.aspx?UTM_A=Georgia&UTM_B=Maryland":
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>
</title></head>
<body>
<form name="form1" method="post" action="Default.aspx?UTM_A=Georgia&UTM_B=Maryland" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUJNzU0OTY1Mjk1ZGRbJc0Q8nWuQUZrihiKtbAzs/+VPA==" />
</div>
<div>
<a id="link" href="http://www.google.com/?UTM_A=Georgia&UTM_B=Maryland" style="background-color:Red;">Google</a>
<br />
<a href="http://www.yahoo.com/">Yahoo</a>
</div>
</form>
</body>
</html>