Tuesday, June 27, 2006

Making Dynamic CSS content with ASP.Net

I had the situation where there was a need to modify a css file on the fly.
It is like the poor man's Theme but it is slightly different.
Let's say you want the H1 background color to be configurable by the user. This
can be achieved via the Profile and by some other means.
For the sake of this demo, I will use the Session state. Let's say I have
a stylesheet like this

H1 { background-color:Red; }

in a file called StyleSheet.css in the application root.

What I want to do is to replace the "Red" with "Blue" for instance according to
some value in the Session. The first naive approach is to read the css in memory and
do a string replace. This is very brittle and just a bad hack. Some may get smarter
and use a regular expression.

The approach I am taking here is the following. We already have something in ASP.Net
that does text substitution! Yep, an aspx page does just that with server side
code injection. So, conceptually what we want is this:

H1 { background-color:<%= ColorManager.Color %> ; }

Where ColorManager is some class we write to get the color from the Session.

As you are aware, css does not support this kind of syntax. Can we just fool the
system to do this? If you are in love with the ASP.Net pipeline, you can....

Step 1 :
We rename StyleSheet.css to StyleSheet.aspx and make a 'page' like this

<%@ Page Language="C#" %> H1 { background-color:<%= ColorManager.Color %>; }

Step 2:
We make ColorManager.cs and put it in App_Code. A static class will do.
For now you can just stub this out like this

public static class ColorManager
{
static public string Color
{
get
{
if (HttpContext.Current.Session["H1COLOR"] == null)
return "red";
return (string)HttpContext.Current.Session["H1COLOR"];
}
set
{
HttpContext.Current.Session["H1COLOR"] = value;
}
}
}

Step 3:
We need to add a link to our dynamic stylesheet from a test page.
The perfect spot to put it is in the <HEAD>.

<head runat="server"> <link rel="stylesheet" href="StyleSheet.aspx" type="text/css" /> </head>

The href is pointing to our StyleSheet.aspx. The browser could not care less about the
address here as long as the type is correctly set to "text/css". The browser will
interpret the web response as a css text (which it is).

Here is the kicker, you can still use Themes with this approach. By using Themes, the
framework will add the css from the Theme directory as <link> in the <HEAD runat="server">
after our own dynamic css.

Here is a test page to tie all this together. Each time you click on the button
the H1 color changes and you can even see the dynamic css by clicking on the "See CSS".

So much power in ASP.Net. The question is how we can take advantage of it.

CF

default.aspx:

<%@ Page Language="C#" AutoEventWireup="true" %>
<script runat="server">
protected void Bt1_Click(object sender, EventArgs e)
{
ColorManager.Color = (ColorManager.Color == "red") ? "blue" : "red";
}
</script>
<html xmlns=" http://www.w3.org/1999/xhtml" >
<head runat="server">
<link rel="stylesheet" href="StyleSheet.aspx" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<H1>Hello World!</H1>
<asp:Button runat="server" ID="Bt1" OnClick="Bt1_Click" Text="Change Color" />
<asp:Hyperlink Text="See CSS" runat="server" ID="ToCSS" NavigateUrl="~/StyleSheet.aspx" />
</form>
</body>
</html>

Thursday, June 15, 2006

A Master Page GotCha...


I was messing around with master pages and found something very strange...

I have a page1.aspx referencing master.master.

I made an override
CreateChildControls()
{
   base.CreateChildControls();
    Controls.InsertAt(0,_MyErrorLink = new HyperLink());
}

I just want to show this debug link on top all the time...

The page comes up but when the page posts, the rendered page is completely blank! No bytes are sent out whatsoever (as Trace="true" proves).

There is no exception raised, it is just blank.

So it seems that the top level of the control hierarchy should always be the master page and monkeying with the sequence in the CreateChildControls is not a good idea.

What I am doing I think is legal since the controls collection is created the same  way everytime.

A bug/limitation I guess. Conclusion, don't do it

CF











__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com