RSS 2.0
Journal / Blog
Saturday, May 31, 2008
The Good Parts of The ASP.NET Framework and Visual Studio
Douglas Crockford opens his latest book with these words:
Most programming languages contain good parts and bad parts. ... [the language designers or architects] are usually powerless to do anything except heap more features on top of the existing pile of imperfections. And the new features do not always interact harmoniously, thus producing more bad parts. - JavaScript: The Good Parts by Douglas Crockford
His words can apply to all programming languages and frameworks. Especially the ASP.NET Framework and Visual Studio.

Bad parts in the ASP.NET Framework and Visual Studio:
  • ASP.NET Themes and Skins
  • The ASP.NET AJAX Framework
  • ASP.NET / Visual Studio Inline Style Properties
  • Visual Studio Design View
  • ASP.NET and Visual Studio's over dependency on XML configuration files
It would be great if someone wrote a book outlining the good parts of ASP.NET and Visual Studio. :)

What bad parts do you steer clear of?

Tuesday, April 08, 2008
A Reflection on Themes, Skins, and Cascading Style Sheets (CSS) in ASP.NET 2.0 (A Final Conclusion)
A couple years ago I was thrown into a web application that made heavy use of ASP.NET Themes and Skins. Prior to this I depended exclusively on Cascading Style Sheet (CSS) for my web development / web design needs. A first glance at ASP.NET Themes and Skins looked promising, but a number of flaws surfaced - see the links and issues listed at the end of this post.

In addition to these issues, here are a couple other considerations when thinking about ASP.NET Themes:
  • Themes do not adequately separate the levels of concerns within your application. When using Themes all design related files are baked into the application. From a maintainability standpoint, this doesn't bode well in large web applications. Hosting design related files on a single server or an external Content Delivery Network (CDN) is an effective way for managing site wide UI updates and increasing a sites performance, ASP.NET Themes works against this technique.
  • Themes add unneeded complexity by obscuring the real technologies at work (CSS). Everything that ASP.NET Themes offer can be better achieved outside of the ASP.NET Theme Framework. Technologies like Cascading Style Sheets (CSS),  alternate Style Sheets, and JavaScript can achieve more than Themes can provide.
  • Themes are a server-side mechanism. Themes become a nuisance in client-side dependent, heavily dynamic, Web 2.0, DHTML, AJAX type web applications.
  • Themes discourage developers from learning more about web design and the technologies surrounding it. Themes offer a seemingly simple API, which shelters developers from the complexities of CSS and JavaScript, but sooner or later The Law of Leaky Abstractions comes into play and knowing the fundamentals of these technologies is a necessity.
  • Professional web designers don't use ASP.NET Themes, CSS is the language of web designers.
Default Skins on the other hand can be useful for defining consistent CSS hooks into common ASP.NET controls. It's unfortunate that we can't use Skins without Themes.

Related posts:

Monday, February 25, 2008
Free: Win a Copy of Professional ASP.NET 2.0 Design: CSS, Themes, and Master Pages
Professional ASP.NET 2.0 Design: CSS, Themes, and Master Pages by Jacob Sanford is a great book for ASP.NET developers looking to expand their knowledge on the ASP.NET 2.0 Web Design front.

I've read this book, re-read it, edited it, and would like to give it away - I was the Technical Editor. The books is like new and (did I mention) it's free!

Contest Rules:

  • Updated! Just Leave a comment with a valid email address!
  • Post a 500 x 200 pixel image of something you're working on in the comments of this post - this image could be code, web design, or anything work related.
  • Include an optional description of your work
  • The winner will be chosen April 1st May 1st, they'll be drawn at random, and will be notified through email.
  • I pay for shipping.
* I've included a sample entry in the comments. If you're looking for a great free photo editing application then try Paint.net. If you're looking to host your image you might want to consider Flickr or Photobucket.

Good Luck!

The contest has ended, and the winner is..... Andrew Hinde. Nice!
Tuesday, April 03, 2007
A Resolution to The Problems with Themes, Skins, and Cascading Style Sheets (CSS) - Putting the Cascades back into ASP.NET 2.0 Themes (taking control over CSS Cascades / Load Order, Media Types, and Overrides)
ASP.NET 2.0 Themes have a couple design flaws, all of which center around the way Themes reference Cascading Style Sheets (CSS). I've been posting Theme and CSS related issues and work arounds as I encountered them, and in one of my first posts I outlined the possibility of using a VirtualPathProvider to ignore the CSS files within a directory. In this post I share David Marzo's implemented of this solution. This resolution resolves most of the issues surrounding Themes and CSS, and essentially puts the Cascades back into CSS.

The Problem / Question:
ASP.NET 2.0 Themes automatically includes all the Style Sheets (.css files) found in the active Theme (App_Theme) directory into the Head of the rendered document. This severely limits the robust CSS language, and works against the last decade of Cascading Style Sheet progress. For more specific details on the problems with ASP.NET 2.0 Themes start reading the articles found here.

A Solution / Work Around:
Add a custom VirtualPathProvider to ignore the Style Sheets (CSS files) found in the App_Theme directory. For more background on this solution see my article and David Ebbo's article titled Overriding ASP.NET combine behavior using a VirtualPathProvider.

An example of the problem:
The directory structure:

Notice all the Style Sheets (.css files), there are more in the Adapters directory too.

Before including the CustomVirtualPathProvider (code provided below) into the project's build - the XHTML rendered by Themes:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>
      The Problems With Themes and Skins in ASP.NET 2.0
</title>
<link href="App_Themes/Default/CSS/Adapters/ChangePassword.css" type="text/css" rel="stylesheet" />

... The other 17 externally linked Style Sheets go here, they were removed to improve readability ...

<link href="App_Themes/Default/CSS/PrinterFriendly.css" type="text/css" rel="stylesheet" />
</head>
<body>
The Style Sheets are automagically inserted into the Head tag from the active Theme directory. Keep in mind that Internet Explorer has a 30 Style Sheet limitation (see article Q262161).
After including the CustomVirtualPathProvider (code provided below) into the project's build - the XHTML rendered by Themes:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head><title>
      The Problems With Themes and Skins in ASP.NET 2.0
</title>
</head>
<body>
Notice the complete lack of Style Sheets - ahhh simplicity is bliss, the very foundations of CSS Zen Enlightenment... :) Now we can manually include our Style Sheets, use Conditional Comments, and so on.
The source code for the CustomVirtualPathProvider provided by David Marzo in C#:

using System;
using System.Data;
using System.Security.Permissions;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;
using System.Collections;

namespace Arfila.Web.Logic {
 
    [AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Medium)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand,
        Level = AspNetHostingPermissionLevel.High)]
    public class CustomVirtualPathProvider : VirtualPathProvider {
       
        public static void AppInitialize() {
            HostingEnvironment.RegisterVirtualPathProvider(new CustomVirtualPathProvider());
        }
       
        public CustomVirtualPathProvider() : base() { }
 
        private bool IsThemeDirectory(string virtualPath) {
            String checkPath = VirtualPathUtility.ToAppRelative(virtualPath);
            return checkPath.StartsWith("~/App_Themes/",
                StringComparison.InvariantCultureIgnoreCase);
        }
 
        public override VirtualDirectory GetDirectory(string virtualDir) {
            if (IsThemeDirectory(virtualDir)) {
                return new ThemeDirectory(Previous.GetDirectory(virtualDir));
            }
            else {
                return Previous.GetDirectory(virtualDir);
            }
        }
    }
 
    [AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand,
        Level = AspNetHostingPermissionLevel.Minimal)]
    public class ThemeDirectory : VirtualDirectory {
 
        VirtualDirectory _toFilter;
        private ArrayList _children = new ArrayList();
        private ArrayList _directories = new ArrayList();
        private ArrayList _files = new ArrayList();
 
        public override IEnumerable Children {
            get { return _children; }
        }
 
        public override IEnumerable Directories {
            get { return _directories; }
        }
 
        public override IEnumerable Files {
            get { return _files; }
        }
 
        public ThemeDirectory(VirtualDirectory toFilter) : base(toFilter.VirtualPath) {
            _toFilter = toFilter;
            BuildChild();
        }
 
        private void BuildChild() {
 
            foreach (VirtualDirectory dirToFilter in _toFilter.Directories) {
                ThemeDirectory themeDir = new ThemeDirectory(dirToFilter);
                _children.Add(themeDir);
                _directories.Add(themeDir);
            }
 
            foreach (VirtualFile fileToFilter in _toFilter.Files) {
                string fileExtension =
                    VirtualPathUtility.GetExtension(fileToFilter.VirtualPath).TrimStart('.');
                if (string.Compare(fileExtension, "css", true) != 0) {
                    _children.Add(fileToFilter);
                    _files.Add(fileToFilter);
                }
                else {
                    //archivo .css no incluir
                }
            }
        }
    }
}
Some of the code has been modified for readability, download the original source code here.

Note: In order to use this VPP you'll have to copy the code above into a new class in your App_Code directory.

Caveat: If a Web site is precompiled for deployment, content provided by a VirtualPathProvider instance is not compiled, and no VirtualPathProvider instances are used by the precompiled site. - Taken from the article titled VirtualPathProvider Class on MSDN.

Conclusion:
This is one of the nicest work arounds or resolution to the issues surrounding ASP.NET 2.0 Themes. It allows us to leverage the power of ASP.NET 2.0 default Skins, allows us to logically group design related resources (Style Sheets, images, default Skins, videos, etc…) in the App_Theme directory, allows us to control the loading order (cascades) of style sheets, allows us to use Conditional Comments, to define Media Types, to override / inherit Styles, and to continue using CSS as it's intended. In addition we can now easily integrate the ASP.NET 2.0 CSS Friendly Control Adapters into our web applications.
Tuesday, March 20, 2007
In Favor of Using Style Elements / Embedded Style Sheets / Style Blocks / Style Tags or Whatever You Want To Call Them inside the HTML / XHTML Body.
I've been using Style Elements within the HTML Body tag to work around some of the design flaws presented in ASP.NET 2.0 Themes - see the second solution in this post for more details. I've been leary of using this method because it's not a best practice, since it compromises the validity of the HTML / XHTML document. I decided to do a little more research on this subject and made the following discoveries.

Discoveries:
  1. Some of the more complex web sites (Amazon and Yahoo!) make use of Style Elements within the Body Element - see the source snippets below.
  2. Gecko (Firefox, Flock, Mozilla, etc…) based browsers automatically move Style Elements found within the Body Element into the Head Element and render the page as expected - see the rendered Document Object Model (DOM) image below.
  3. Internet Explorer doesn't move the Style Element into the Head Element, but renders the page as expected.
  4. Opera… well I wish I knew what Opera did, but the page renders as expected.
Source snippet from Amazon:
</table>
    </td>
  </tr>
</table>

<style type="text/css">
.lol-hr-center { margin: 5px; border-top-width: 1px;
/* and so on... */
}
</style>


<div id="listoflists_data" style="display:none">
Note how the Style element is located between the <table> and <div> tags.
Source snippet from Yahoo!:

<h4>
<
a id="paweather" class="details" href="r/wb/*-http://weather.yahoo.com/forecast/USKS0448_f.html"><span class="icon">Weather <b><strong>51&deg;</strong>F</b></span></a>

<style type="text/css">#patabs #weather .icon{background:url(http://us.i1.yimg.com/us.yimg.com/i/us/we/31/b/26.gif) 3px 2pxno-repeat;}</style>

</h4>
Note how the Style element is located within the <h4> tag.

A snapshot of the Document Object Model (DOM) as seen through Firebug:

Note the highlighted area references the Yahoo! source snippet from above.
Conclusion: Although the Style Element within the Body Element compromises the validity of a document, some of the leaders in web design and accessibility use this approach, so it may not be as big a work around or hack.

Sunday, February 25, 2007
The Problems with Themes, Skins, and Cascading Style Sheets (CSS) in ASP.NET 2.0 – Creating Printer Friendly Pages (defining a CSS Print Media Type) with CSS While Using Themes (Work Around #5)

In this post I outline a couple alternate ways of defining the CSS Print Media Type with Themes. ASP.NET 2.0’s Themes and Skins have a number of design flaws - Themes and Skins depend almost entirely on Cascading Style Sheets (CSS), but don’t fully support CSS - I’ve listed some "Work Arounds" for a couple design flaws. I don’t recommend any of these "Work Arounds" since they contribute to software entropy before your application is even developed, instead I suggest sticking with CSS and perhaps using some default Skins that define CSS selectors like classes or IDs.

The Problem / Question:
How can I use the CSS Print Media Type with Themes? In the past I've used an External Style Sheet which defined the Print Media Type, but ASP.NET 2.0 omits the Media Type attribute when it automatically includes all my CSS files (from the active Theme directory) into the HTML Head tag.

A Solution / Work Around:
The Print Media Type isn't constrained to External Style Sheets and can be defined in the Style Element, in the @Media rule, and even specified through the @Import rule.

An example of the problem:
The directory structure:


The rendered XHTML:
<head>
    <title>The Problems With Themes and Skins in ASP.NET 2.0</title>
    <link href="App_Themes/Default/PrinterFriendlyStyleSheet.css"
     type="text/css" rel="stylesheet" />
    <link href="App_Themes/Default/StyleSheet.css"
     type="text/css" rel="stylesheet" />
</head>
Note each externally linked Style Sheet lacks a media type.

Our desired XHTML (using an Externally Linked Style Sheet and a Print Media Type) would have looked something like this:
<head>
    <link href="App_Themes/Default/PrinterFriendlyStyleSheet.css"
     type="text/css" rel="stylesheet" media="all" />
    <link href="App_Themes/Default/PrinterFriendlyStyleSheet.css"
     type="text/css" rel="stylesheet" media="print" />
</head>
Note the Media Type (media="print") in bold.
The solutions:
1. Use the Media Rule (@Media) to define the print Media Type inside an Externally Linked Style Sheet.
An example:
@Media Print {
      body {
            background-color: #FFFFFF;
      }
      /*... your CSS here ...*/
      #Menu, #AdvertismentContainer {
            display: none;
      }
      #Content {
            width: 100%;
      }
}
Discussion: This is probably the best alternative to defining the Media Type in an Externally Linked Style Sheet - the other solutions introduce problems of their own.
2. Use the Import Rule (@Import) to load your printer friendly Style Sheet from an alternate location and define a Media Type - this involves removing your printer friendly Style Sheet from the Themes (App_Theme directory).
An example:
@Import url("/AppName/CSS/PrinterFriendlyStyleSheet.css") Print;

Discussion: This solution requires moving our Printer Friendly Style Sheet outside the Theme directory, since Themes don't allow us to exclude a Style Sheet folder (see Excluding a CSS folder for more details). Once we start moving Style Sheets outside the Themes directory we should probably ask ourselves why we're even using Themes, and consider regaining complete control over our CSS by moving all the CSS files outside the Theme directory. At this point we could revert to Externally Linking our Style Sheets where we could define our Media Type attributes. In addition the CSS URL function used in this solution confuses many.
3. Use the Style Element to define a Print Media Type.
An example:
<style type="text/css" media="print">
    /*... your CSS here ...*/
</style>

Discussion: This solution doesn't work if the Style Elements are defined in the HTML head (see Using Internal (Embedded) Style Sheets with Themes for more details), you can however move the Style Element into the Body of the document, this compromises the HTML validation, but large e-commerce sites like Amazon and Yahoo! make heavy use of this method.
4. Sub class the HtmlHead class to enumerate through the child controls and add new Meta attributes to the child controls using the HtmlLink class. See my post titled Defining a Media Type(s) for more details.
Discussion: This solution requires a fair amount of work and only solves one of the many problems with Themes, pursuing this solution would probably be a case of not seeing the forest for the trees.
In conclusion; Themes are a nice addition to ASP.NET, but have some significant design flaws particularly in the way it uses CSS - in this case how printer friendly (print) CSS Media Types are defined. I wouldn't recommend using Themes on a complex web applications that make heavy use of CSS or AJAX, but for small projects they may be a nice option.

Related links:
Related posts:
Monday, February 05, 2007
The Problems with Themes, Skins, and Cascading Style Sheets (CSS) in ASP.NET 2.0 – Using Internal (Embedded) Style Sheets with Themes (Work Around #4)
ASP.NET 2.0’s Themes and Skins have a number of design flaws - Themes and Skins depend almost entirely on Cascading Stye Sheet (CSS), but don’t fully support CSS - I’ve listed some "Work Arounds" for a couple design flaws. I don’t recommend any of these "Work Arounds" since they contribute to software entropy before your application is even developed, instead I suggest sticking with CSS and perhaps using some default Skins that define CSS selectors like classes or IDs.

The Problem / Question:
How can I add Internal (embedded) style sheets (the ones that use the Style element) inside the Head tag when using Master Pages and Themes?  How can I override (overload) External style sheets for local pages or specific Web User Controls?

A Solution / Work Around:
One option is to create an ASP Placeholder (asp:contentplaceholder) in the Master Page's Head tag to add the Style element into the Head of your Web Form (.aspx page). However, this solution doesn't work well when using Themes, since themes automatically include the External style sheets after the Style element - I demonstrate this and provide an alternative solution later on in this post.

The Caveat / Warnings:
In most current-generation browsers the loading order for Internal style sheets, and External style sheets depend on their position in the Head tag. This behavior seems to go against what the W3C intended.
Generally speaking we can say that all the styles will "cascade" into a new "virtual" style sheet by the following rules, where number four has the highest priority:
  1. Browser default
  2. External style sheet
  3. Internal style sheet (inside the <head> tag)
  4. Inline style (inside an HTML element)
- Taken from: http://www.w3schools.com/css/css_intro.asp
As I understand and as the w3schools point out (I can't find a reference from the depths of the W3C), Internal style sheets should have a higher priority than External style sheets, unfortunately this isn't the reality. Instead External style sheets and Internal style sheets depend on the loading (cascading) order. An Internal style sheet will only override an External style sheet (in current-generation browsers) if the External style sheet is loaded first. This behavior introduces problems when using an ASP Placeholder because ASP.NET automatically includes the Style Sheets (.css) from the active Theme (App_Theme) directories into the Head tag after the ASP Placeholder's contents have been loaded.

An example of the problem:
The directory structure:

The active Master Page:
<%@ Master Language="C#" EnableTheming="true" AutoEventWireup="true"
CodeFile
="MasterPage.master.cs" Inherits="MasterPage" %>

<!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>The Problems With Themes and Skins in ASP.NET 2.0</title>

    <asp:contentplaceholder id="ContentPlaceHolderHead" runat="server" />

</head>
<
body>
    <form id="form1" runat="server">

        <h1>Hello World!</h1>

    </form>
</
body>
</html>
Note: the ASP Content Place Holder between the Head tags and "Hello World!" between the H1 tags.

The default Web Form (.aspx page) providing the Content for the Master Page's Content Place Holder:
<%@ Page Language="C#" Theme="Default" MasterPageFile="~/MasterPage.master"
AutoEventWireup
="true" CodeFile="Default.aspx.cs" Inherits="Default" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolderHead" Runat="Server">

    <style type="text/css">
   
H1{
        color: red;
    }
    </style>

</asp:Content>
Note: the Style element between the ASP Content Place Holder tag - H1 should now be colored red.

The contents of StyleSheet.css, the only CSS file in the Active Theme (App_Theme) directory:
H1{
      color: blue;
}

Note: H1 should still be red because Internal style sheets are supposed to have priority over External style sheets.

The rendered XHTML:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"