comments edit

Tonight at Soccer practice, we scrimmaged for a while then ran through some drills.  We have an English guy and a Scottish guy (who hardly anyone can understand) on the team who are a laugh a minute.  You can imagine their surprise when we started a shooting drill and our team manager tells them that we all have to shag our own balls.

comments edit

Seems like all sorts of open source projects have been releasing lately.  Darren Neimke and Keyvan Nayyeri proudly announce the release of BlogML 2.0 on CodePlex.  Here’s a list of new features on Keyvan’s blog. With a bit of luck and lots of persistence, BlogML will hopefully be a key component in breaking vendor lock-in when it comes to blogging engine. 

For example, if you decide to try Subtext as your blogging engine, and decide it’s not for you, I want you to have your data in a form that is easy to import to other engines.  Why should you have to write code to move from one platform to another?

I contributed a BlogML provider framework with the goal of making it really easy to implement BlogML on other platforms.  For example, the homegrown blog.  I don’t feel I fully accomplished the goal of making it easy, but I think it’s a step in the right direction and I’m sure it’s in good hands now.

Of course I am now pissed (for you British, that’s angry, not drunk) that we have all this extra work to do for Subtext since we’re still running BlogML 1.0 (legacy!), and 2.0 has already been out a few hours!

comments edit

Darren Neimke apparently is not one to shy away from a bit of trash talk.  He IM’d me via MSN recently to warn me about a new SUB, ready to take down Subtext. In this case, it is his newly open sourced blog engine, SingleUserBlog or SUB, which is now hosted on CodePlex.  Darren has been on a roll lately with the recent release of BlogML 2.0.  Now SUB enters the scene with torpedoes blazing!

But Darren must know he is not dealing with a complete novice in warfare.  I deftly guided him to choose the BSD license.  So should they implement something I must have, I can just take it, BWAHAHA! (with proper attribution of course, following all terms of the license and other legal mumbo jumbo)

Darren, I believe I sunk your battleship.

comments edit

SceneryThis past weekend my wife and I drove up to San Francisco to attend a friend’s wedding, which ended up being a lot of fun.  We always like visiting The City because of the many friends we have in the area, though being there reinforces the fact that it is not a place where we’d want to live (no offense to anybody who lives there, it’s just not our style).

While up there we were fortunate enough to have dinner with Mr. Coding Horror Jeff Atwood and his wonderful wife.

They gave us a tour of their new place and I was most impressed with his “boom boom” room (it’s his term and it’s not what you think).  They have a separated room tricked out with surround sound THX speakers, an LCD Projector, a Play Station 2, Dance Dance Revolution game pads, and of course, Guitar Hero.  Jeff gave us a quick demo of Guitar Hero and I was quite impressed, both by the fact that Jeff has some rhythm as well as the graphics and sound of the game.

franciscoIn some ways, the boom boom room reminded me of Ricky Shroder’s room from Silver Spoons.

Meanwhile, my brother is moving from Alaska to Minnesota, but he’s doing it the hard way, driving.  He drove down to Los Angeles from Anchorage, Alaska at a relatively leisurely pace visiting with friends along the way.

He will stay with us for a couple of days and then he and I will set out to drive to Minnesota.  My parents are such worriers so it made them feel better that I was driving with him for this leg of the trip since he won’t be stopping much.

Hopefully we’ll get there with enough time to visit some relative we have in the area.  In any case, if I am less than responsive to emails and Subtext mailing list/forums, you’ll know why.

comments edit

I mentioned several heuristic approachs to blocking spam in my recent post on blocking comment spam, but commenters note that I failed to mention CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart).  At the moment, CAPTCHA is quite effective, both at blocking spam and annoying users.

But I don’t have any real beef with CAPTCHA, apart from the accessibility issues.  If I met CAPTCHA in a bar, I’d buy it a beer! No hard feelings despite thetrash talkingin the past, right?

There is successful code out there that can break CAPTCHA, but that is pretty much true of every other method of blocking spam I’ve mentioned.

The reason I didn’t mention CAPTCHA is that it would be ineffective for me.  Much of my spam comes in via automated means such as a trackback/pingback .  The whole point of a trackback is to allow another computer to post a comment on my site.  So telling a computer apart from a human in that situation is pointless.

And at the moment, the Comment API has no support for CAPTCHA.  If comment spam isn’t coming in via the comment api now, it is only a matter of time before it is the primary source of comments.

So while I believe CAPTCHA is effective and may well be for a good while until comment spammers catch up, I would like to look one step ahead and focus on heuristics that can salvage the use of trackbacks and the Comment API. 

comments edit

As a follow-up to the recent release of Subtext 1.9, I would also like to introduce a little something I put together at

Since we have yet to incorporate a skin preview or gallery in Subtext, I setup a site that features each of the default skins.  Additionaly, the site also has a Skin Showcase where users can submit skins to share with the community.  User submissions are moderated.

Subtext Skins

Although we plan to overhaul skinning in the next version, it is still worthwhile to share skins here as my hope is to help port any user submitted skin (unless it gets too ridiculous in there).

I started off the sharing with the Marvin 3 Column skin which used to be included with Subtext.  If you have a skin you wish to share, please do share!  I recommend that your zip file include a Skins.User.config file rather than a Skins.config file.

comments edit

Logo Well my friends, it took a bit longer than expected to get Subtext 1.9 out the door, but we did it.  When we released Subtext 1.5 back in June I said,

The next version of Subtext is code named Daedelus. It will simply be a straight upgrade to ASP.NET 2.0. We hope for a quick turnaround as we don’t plan to add a lot of features in this iteration. We just want to get up and running in ASP.NET 2.0.

Well that was then and this is now and I was wrong about the quick turnaround.

We realized that a straight port to ASP.NET 2.0 wasn’t much fun if we couldn’t take advantage of some of the new goodies that ASP.NET 2.0 has.  So we spent a significant amount of time cleaning up code and refactoring some functionality to take advantage of what ASP.NET 2.0 offers.  A lot of the changes are under the hood, but there are still a few surface level treats for everybody.

Before you upgrade to 1.9, please check out my notes on upgrading.

So what is new in Subtext 1.9 besides that it is now an ASP.NET 2.0 application?

Under The Hood

Let’s not kid ourselves. 99.999% (Five nines baby!) of my readers are geeks and we want to pop open the hood and take a look around.

  1. Subtext Providers have been refactored to use the Microsoft base Provider class, System.Configuration.Provider.ProviderBase.
  2. Used Generics where appropriate.  As you know, there is a lot of temptation when given a new hammer to start looking at everything as a nail.  We tried to avoid that temptation and make judicious use of Generics.  I think we did a bang up job.  Most of our collection classes are now generic collections and there’s that CollectionBook class I wrote about recently.
  3. Improved our Continuous Integration and build process using CruiseControl.NET.  We now have a nice dashboard that provides a lot of visibility into our development progress.
  4. Improved our unit test code coverage to 36.4% and counting. (When I started it was pretty much 0)
  5. Subtext now runs under Medium Trust without problems except for the Trackback/Pingback issue.
  6. Converted the Subtext.Web project into a Web Application Project.
  7. Added a _System folder to the Skins directory. This contains some CSS files that any skin may reference which provide some common CSS layout and styles.  For example, by referencing commonstyle.css, you can use the pullout css class to pullout some text.  Custom skins can reference these files and override specific settings, putting the Cascading back in CSS.

Try out the new “pullout” or “pullout.alt” CSS classes.

New Features

Some new features we added.

  1. Sometimes removing code is as much a feature as adding code.  As I announced earlier, we removed some old skins and added some snazzy new ones.  We also implemented a way for custom skin definitions to not get overwritten when upgrading code.
  2. Improvements to the packaged skins.  We added the Previous/Next control to nearly every skin as well as Gravatar support among other minor improvements.
  3. Comment Moderation!  This high demand feature was fast-tracked when my company was hired to implement it for a client who wished to start a blog. The client agreed to contribute the source back to the project!
  4. Not exactly a new feature, but we changed the default Html Editor to use the FCKEditor.
  5. Implemented RSD (Really Simple Discovery) and the MetaWeblog API’s newMediaObject method so that Subtext works quite well with Windows Live Writer.

Bug Fixes

There are probably too many to list, but I’ll point out a few that people may have noticed.

  1. [1524172] The Username is being saved as the title.
  2. [1524371] Non-English comments do not appear correctly in mail message.
  3. [1521317] Installation check code fails in locked down scenarios.
  4. [1519764] Skin selection not retained.

Important Note

Subtext ships with ReverseDOS spam blocker enabled out of the box. Please check the ReverseDOS.config file to make sure that it is not filtering any terms that would be relevant to comments in your blog. You can also disable ReverseDOS by removing any reference to it from Web.config should you so desire.

Plans For The Future

We are now gearing up for Subtext 2.0 “Poseidon”, our next major release, which will feature a plugin framework.  Our hope is to foster a community of plugin contributions.  Other features in the works include a Membership provider which will allow multiple authors for a single blog and a new skinning framework. I will update the Roadmap soon to reflect our current plans for 2.0.

Also, with the recent deluge in comment spam, I am considering having an interim release (1.9.1) that would include Akismet as well as semi-moderation (1.9 does include full moderation now). Ideally we would save these features until we have a plugin framework, as they seem like great candidates for plugins. However the communal benefit of blocking spam may be too great to wait.

Many thanks to the growing numbers of Subtext contributors who helped shape and test this release.  All your efforts, whether it is coding, submitting patches, testing, reporting bugs, requesting features, or just giving us a piece of your mind are appreciated!

And before I forget, as I tend to do, the link to the latest release is here.

comments edit

I am still continuing my experiment in running as a LUA (aka Non-Admin).  Let me tell you, it has been a total pain in the ass and now I totally understand why more developers do not do this, which feeds into the vicious cycle in which apps are developed that do not run well under least user privileges.  When I have some time, I will write up my experiences.

One tool that has been invaluable in this experiment is the MakeMeAdmin batch file used to temporarily elevate your privilegs in a command window.  This has worked nicely for me for a while.


Then Scott Hanselman points out Console that takes cmd.exe and adds transparency and tabs.  Just pure geek hotness that I gotta have.

However, the only command shell I normally keep open is my MakeMeAdmin shell.  It’d be a shame to install Console and never see its sleek hotness.  So I decided to play matchmaker and see if I could marry these two wonderful utilities.

I modified the MakeMeAdmin.bat file to use Console instead.  It was a one line change (note file paths should be changed to fit your setup and the line break in there is for formatting purposes. There shouldn’t be a line break.).

set _Prog_="console.exe c:\console_admin.xml 
    -t """*** %* As Admin ***""""

I also created a new admin config file named console_admin.xml that specifies transparency and a red tint which lets me know that this console window is not like the others. It will run commands as an admin.

I’ve uploaded my modified MakeMeAdmin.bat file as well as the console configuration file to my company’s tool site here.  Hopefully all five of you out there also running as a non-admin will find this useful.

tags: LUA, Least User Account, NonAdmin

comments edit

Let me start off by noting that Subtext 1.9 requires ASP.NET 2.0!  Thus the upgrade process from a prior version of Subtext (all which run on ASP.NET 1.1) will not be quite as simple as before, but should hopefully not be overly complicated as is the spirit of Subtext.

For Users Who Have Control Of Their Hosting Server

Users who host on their own server, or have Remote Desktop access to their hosting server will have an easier time with the upgrade.  My recommendation is to simply setup a new folder with the new version of Subtext, copy in your modifications, and then switch IIS over to ASP.NET 2.0 to point to the new directory.  The following is a step-by-step detailed procedure.

  1. Backup your Database.This should go without saying.
  2. While you are in Enterprise Manager, make sure the database user that your blog uses to access the database has DBO permissions temporarily.  This is required so that the web-based upgrade procedure will work.
  3. Make sure you can login to the HostAdmin section.  On most blogs this would be the /HostAdmin/ directory of the site. For example, on my blog the HostAdmin is located at  If you forget your HostAdmin password, there is a query you can run in Query Analyzer to reset your password at the bottom of this page.
  4. Download and unzip the Subtext 1.9 binaries into a new directory parallel to your current installation.  For example, on my server I host my blog in the d:\Websites\\ directory.  When upgrading to Subtext 1.9, I unzipped the distribution to the following path d:\Websites\\.
  5. Merge any customizations from your old web.config file into the new web.config file.  Be sure to note that some settings have moved. For example, the connection string has been moved into the <ConnectionStrings> section.  Also take a look at any new settings you may be interested in.
  6. Copy all your images, videos, audio files and any other non-Subtext files and customizations into the appropriate place in the new directory.For example, I copied the images folder as well as my own Demos folder which contained some demo code on my site into the folder.
  7. Now in IIS Manager, configure your existing site to use ASP.NET 2.0 and point it to your new directory.  For details, see the section at the bottom of this post.  You may need to change the Application Pool your site runs in if you are running Windows 2003.
  8. Visit your website and follow the instructions. At this point, the normal web-based upgrade wizard should kick in, asking you to login to the HostAdmin tool and click the upgrade button.  This will upgrade your database schema and stored procedures.
  9. Make sure to reverse the change you made in step 2!  Subtext does not require DBO permissions for normal operations. The user that Subtext uses to connect to your database should just be in the public group.

For Users With Hosted Solutions Such as WebHost4Life

Unfortunately I am not familiar with the procedure that the various hosting providers use to upgrade a site from ASP.NET 1.1 to ASP.NET 2.0.  If the upgrade happens on the same machine that your site is currently hosted in, the upgrade may bring down your site for a short bit.  You may have to coordinate the above steps with a technician at your hosting company, except for the following changes.

  • Step 4: Download and unzip the Subtext 1.9 binaries to your local machine.
  • Step 6: Have your hosting support technician upgrade your site to ASP.NET 2.0
  • Step 7:  Copy your local files over to your hosting provider.

Configuring IIS for ASP.NET 2.0

To configure a website in IIS for ASP.NET 2.0, right click on the website in the IIS Manager tool and select properties. Click on the ASP.NET tab in the dialog box. It should look something like this…

ASP.NET Version

Makes sure to select 2.0.50727 in the ASP.NET version dropdown.

On Windows 2003, I created a separate Application Pool for my ASP.NET 2.0 websites.  To select the Application Pool for a website, cilck on the Virtual Directory tab and select the Application Pool in the dropdown at the bottom of the dialog as in the following screenshot.

App Pool

Good luck and smooth sailing!

comments edit

Scott Hanselman sets the geek-o-sphere abuzz with his latest (and apparently now annual) Ultimate Developer and Power Users Tool List for Windows.  The publishing of this list usually coincides with a productivity drop for me as I find many new toys to play with.  Unfortunately, many tools don’t work so well when running as a non-admin.

This year I was pleased to find my name and my humble little blog on his list.  Quite pleased in fact until it struck me. 

Wait one doggone minute!

Is Scott calling me a tool?  An ultimate tool no less.  We’ll see about that!

comments edit

Scott writes about making DasBlog work on Mobile Devices.  The approach he takes is to programmatically detect that the device is a mobile device and then present an optimized TinyHTML (his term) theme.

Ideally though, wouldn’t it be nice to have mobile versions of every theme?  In fact, I thought this could be handled without any code at all via CSS media types.

Unfortunately (or is that fortunately) I don’t own a BlackBerry or any such mobile device with a web browser, so I can’t test this, but in theory, another approach would be to declare a CSS file specifically for mobile devices like so:

<link rel="stylesheet" href="mobile.css" type="text/css" 
    media="handheld" />

The mobile browser should use this CSS to render its screen while a regular browser would ignore this.  Should being the operative word here.  Unfortunately, at least for Scott’s Blackberry, it doesn’t.  He told me he does include a mobile stylesheet declaration and the BlackBerry doesn’t pick it up.  Does anyone know which devices, if any, do support this attribute?

For those devices that do, a skin in subtext can be made mobile ready by specifing the media attribute in the Style element of Skin.config like so (note this feature is available in Subtext 1.5).

<Style href="mobile.css" media="handheld" />

Refer to my recent overview of Subtext skinning to see the media attribute in play for printable views, which does seem to work for IE and Firefox.

comments edit

Update: Rob renamed his project to Subsonic.

Rob Conery just released ASP.NET ActionPack 1.0.1 on his blog today.  This project is definitely one to watch!  He is essentially taking some of the principles of developing web apps with Ruby on Rails and porting those ideas to ASP.NET.  Just watch this great screencast to get a taste of the progress he has made in a short time.

So far I am very impressed with this guy.  Yesterday evening I sent the link to the screencast to Jon Galloway who then wondered why he was using strings for table names.  I told him to quit bothering me about it and post something in the Codeplex forum.  But Jon, being the simultaneous type of guy he is, had already posted a comment on Rob’s blog before I could finish my sentence.  This all happened last night.  This morning I notice the sixth bullet point in Rob’s announcement states that he added struct in classes for column names.  Apparently he had received the comment, made the change, and sent a reply to Jon in two hours.

Now that is a quick turnaround and good customer service! ;)

Not only that, but this guy lives in Kuaui, Hawaii! I don’t know how he gets anything done unless it’s the rainy season right now. Subtext would definitely languish if I lived in Kuaui.

comments edit

SpamLately my blog has been hit with a torrential downpour of comment spam.  I’ve been able to fight much of it off with some creative regular

expressions in my ReverseDos configuration file.  Of course keyword filtering, even Bayesian filtering, can only go so far.  We need to supplement these approaches with something else.

But first, in order to combat SPAM, we need to identify the enemy.  Are we fighting against automated bots relentlessly crawling the web and posting comments?  Or are these low paid humans behind the keywords?  Are they attacking via the Comment API or posting to an HTML form?

My assumption has been that these are bots, but I plan to add some diagnostics to my blog to test that assumption someday soon.  Lets run with the assumption that the bulk of comment spam is generated by bots.  In this case, we need to examine the behavioral differences between bots and humans for clues in how to combat spam.

For example, an automated script can pretty much post a spam comment instantaneously.  What if your blog engine timed the interval between sending out the content and receiving a comment?If the comment came back too quickly, then we have high confidence that it is spam.

Certainly this is easily defeated by a spammer by adding a delay, but an artificial delay is costly to an automated script trying to hit the most blogs possible in the shortest amount of time.  Anything to slow down the spammers is worthwhile.

Another potential approach is to require javascript to comment.  Perhaps your comment form doesn’t even exist without some javascript to insert it in there.  The theory behind this approach is that most automated scripts won’t evaluate javascript. They simply want to post to some form fields.  Unfortunately this hinders the accessibility of your site for users who turn off javascript, but it may be worth the price.  Spammers will eventually figure this one out too, but it does add a nice computation cost to implement javascript handling in an automated spambot.

Ultimately, these approaches are more about the behavior of the spammer than the content.  For example, when I first started working on Subtext, I added two features that at the time blocked a significant amount of spam for me.  The first was to not allow duplicate comments.  I found that a lot of comment spam simply posted the same thing over and over.

The second feature was to require a delay between comment spam originating from the same IP address.  Using a sliding timeout of only two minutes seemed to defuse spam bombs which would try to post a large number of comments in a short period of time.

Later, I added ReverseDOS to help catch the spam that made it through these approaches.  Over time, I’ve noticed that comment spam starts to look more and more like legitimate messages, like the current crop of “Nice Site!” spam. 

The one thing that every comment spam has in common is a link.  Ultimately, the only way to stop content spam via a content-based approach is to simply not allow any comment that contains a link in any way shape or form.  But how awful would that be for the many legitimate commenters who wish to share a link?

No, we must do something better. I currently don’t think we’ll ever win the battle, but we can work to stay one step ahead.

comments edit

The other tactic I neglected to mention in my previous post on combatting comment spam is more big picture.  How do we remove the incentive for spammers to comment spam in the first place?

Apparently the rel=”nofollow” approach has done little to curb comment spammers despite many predictions (including my own).  I still think it is an important step in removing one incentive, but what else can be done to remove this incentive?

With the lack of results from the rel=”nofollow” approach, the lesson we learn is that either the incentive for comment spam isn’t necessarily Google rankings or that there are enough unpatched blogs out in the wild that it still does help the google rank to post comments indiscriminately.  Or both.

If a spam commenter can put a link in the comments of several thousand blogs, then certainly that translates to tens to hundreds of thousands of eyeballs on that link, and maybe a few hundred clickthroughs (yes, I’m pulling these numbers out of my rear).  When someone clicks through, the spammer gets paid a small amount from the owner of the site.

Warning, here is where I go off the deep end in brainstorming solutions.  Forgive my naivete.

What if the marketers who pay for these links to be spread around found out that comment spammers were creating negative feelings for their products by posting comments on sites that were vehemently against having these advertisements.  Would they care?  Would they be interested in not paying for click throughs from sites who have specifically opted-out of such links? 

I’m probably dreaming here, but stay with me for a moment as I flesh out a quick thought experiment.  Suppose these sites did care.  One option is for them to not pay for links that originate from sites that specifically opt-out of comment advertising.  For example, by registering with some central opt-out site.

Another approach would be for sites that receive click-throughs to initiate a trackback like mechanism in which they request a comment spam policy from the blog.  If the blog does not explicitely endorse their product, the link does not get paid.

Of course the big flaw in this experiment is that these sites probably do not care and wouldn’t go to the trouble to implement these approaches to being a good citizen.  They just want the links to come in.  Even negative publicity is good publicity.  So what can we do? Is there a way to make them care? Is there a way to make comment spam less lucrative?

comments edit


Another blog linked to this post and mentioned watching the video up to the slow motion practice session.  Be sure to keep watching past it to see the woman juggling a soccer ball, while playing double dutch, with a flaming soccer ball and jump rope.  Ronaldinho never did that!

comments edit

With the Subtext 1.9 release just around the corner, this is probably a good time to highlight some minor, but important, changes to skinning in Subtext.

We made some breaking changes to Skins.config file format to make the naming more consistent with the purpose.  There was a lot of confusion before.  The following is a snippet from a pre-Subtext 1.9 Skins.config file.

<?xml version="1.0"?>
<SkinTemplates xmlns:xsd="" 
    <SkinTemplate SkinID="RedBook" 
        <Script Src="~/Admin/Resources/Scripts/niceForms.js" />
        <Style href="niceforms-default.css" />
        <Style href="print.css" media="print" />

And here is how that snippet will change in Subtext 1.9.

<?xml version="1.0"?>
<SkinTemplates xmlns:xsd="" 
    <SkinTemplate Name="RedBook" 
        <Script Src="~/Admin/Resources/Scripts/niceForms.js" />
        <Style href="niceforms-default.css" />
        <Style href="print.css" media="print" />

The key differences are in the SkinTemplate element. The following attributes have been renamed:

  • SkinID was changed to Name
  • Skin was changed to TemplateFolder
  • SecondaryCss was changed to StyleSheet

Another new change is that the Style element now supports a new attribute named conditional. If specified, Subtext will wrap the stylesheet declaration with an IE specific conditional comment. This is commonly used for stylesheets that contain IE specific CSS hacks. For example…

<Style href="IEHacks.css" conditional="if ie" />

Gets rendered as…

<!--[if ie]>
<Style href="IEHacks.css" conditional="if IE" />

Thus only IE will see that style declaration.

tags: Subtext, Skinning, Skins, Blogs

subtext, open source comments edit

In my previous post, I outlined some minor changes to the skinning model for Subtext. In this post, I will give a high level overview of how skinning works in Subtext.

Subtext renders a Skin by combining a set of CSS stylesheets with a set of .ascx controls located in a specific skin folder.  If you look in the Skins directory for example, you might see a set of folders like this.

Subtext Skin

Skin Template

A common misperception is that each folder represents a Skin.  In fact, each folder represents something we call a Skin Template, and can be used to render multiple skins.  One way to think of it is that each folder contains a family of skins.

Each folder contains a series of .ascx controls used to render each skin in that skin family as well as some CSS stylesheets and images used for individual skins or for the entire family.

For example, the Redbook template folder contains three skins, Redbook, BlueBook, and GreenBook.  In the screenshot below, we can see that there are three CSS stylesheets that specifically correspond to these three skins.  How does Subtext know that these three stylsheets define three different skins while the other stylesheets in this folder do not?


The answer is that this is defined within the Skins.config file.


The Skins.config file is located in the Admin directory and contains an XML definition for every skin.  Here is a snippet of the file containing the definition for the Redbook family of skins. This snippet shows the definition of the BlueBook skin.

<?xml version="1.0"?>
<SkinTemplates  xmlns:xsd="" 
    <SkinTemplate Name="BlueBook" 
        <Script Src="~/Admin/Resources/Scripts/niceForms.js" />
        <Style href="~/skins/_System/csharp.css" />
        <Style href="~/skins/_System/commonstyle.css" />
        <Style href="~/skins/_System/commonlayout.css" />
        <Style href="niceforms-default.css" />
        <Style href="print.css" media="print" />

There is a SkinTemplate node for each Skin within the system (I know, not quite consistent now that I think of it. Should probably be named Skin). 

The Name attribute defines the name of this particular skin. 

The TemplateFolder attribute specifies the physical skin template folder in which the all the ascx controls and images are located in. 

The StyleSheet attribute specifies which stylesheet defines the primary CSS stylesheet for this skin. 

For example, the GreenBook skin definition looks just like the BlueBook skin definition except that the StyleSheet attribute references Green.css instead of Blue.css.

Within the SkinTemplate node is a collection of Script nodes and a collection of Style nodes.  These specify any client scripts (such as Javascript) and other CSS files that should be included when rendering this skin.  As you can see, the tilde (~) syntax works for specifying a path to a file and a developer can specify a media and a conditional for each CSS stylesheet.


I keep mentioning that Subtext depends on a collection of .ascx user controls when it renders a family of skins. Let’s talk about them for a moment. 

In the second screenshot above, you may have noticed a directory named Controls.  This contains the bulk of the .ascx controls used to render a specific skin.  There was also a control named PageTemplate.ascx in the parent directory.


Each skin in a family of skins is rendered by the same set of UserControl instances.  The only difference between two skins within the same family is the CSS stylesheet used (which can account for quite a difference as we learn from CSS Zen Garden).

The PageTemplate.ascx control defines the overall template for a skin, and then each of these user controls in the Controls directory is responsible for archiving a specific portion of the blog.

Select a different skin from another skin family, and Subtext will load in a completely different set of UserControl files, that all follow the same naming convention.

Drawbacks and Future Direction

This is one of the drawbacks to the current implementation.  For example, rather than using data binding syntax, each .ascx file is required to define certain WebControl instances with specific IDs.  The underlying Subtext code then performs a FindControl searching for these specific controls and sets their values in order to populate them.  This naming convention is often the most confusing part of implementing a new skin for developers.

It used to be that if a WebControl was removed from an .ascx file (perhaps you didn’t want to display a particular piece of information), this would cause an exception as Subtext could not find that control. We’ve tried to remedy that as much as possible.

In the future, we hope to implement a more flexible MasterPage based approach in which the underlying code provides a rich data source and each skin can bind to whichever data it wishes to display via data binding syntax.

From a software perspective, this changes the dependency arrow in the opposite direction.  Rather than the underlying code having to know exactly which controls a skin must provide, it will simply provide data and it is up to the individual skin to pick and choose which data it wishes to bind to.


We provided the Naked skin so that developers creating custom skins could play around with an absolutely bare-bone skin and see just how each of the controls participates in rendering a blog.

tags: Subtext, Skins, Skinning, Blogs

comments edit

This is my third post about Skinning in Subtext. Previously I talked about some breaking changes.  Then I gave a high level overview of skinning in Subtext.  In this post I want to mention one new feature for those who use custom skins.

Subtext 1.9 actually reduces the the number of pre-packaged skins that come with it out of the box.  That’s right, we got rid of the skins that screamed, “Hey! I was designed by a developer who wears plaid pants with flannel shirts!”.  Over time, we hope to add more polished designs.

Of course we don’t want to leave developers with custom developer designed skins out in a lurch.  Taking an informal poll I found that a majority of Subtext users deploy a custom skin typically based on one of the out-of-the-box skins. 

As I described in the overview, skins are configured via a file named Skins.config.  One problem with having all the skin definitions in this file is that any customizations a user might make are overwritten when upgrading to a new version of Subtext.

It is incumbent upon the user to merge new changes in.  We thought we could make this better so we have introduced the new Skins.User.config file.

The format for this file is exactly the same as the format for Skins.config.  The only difference is that we do not include such a file in the Subtext distribution.  Thus you can place your custom skin definitions in this file and it will not get overwritten when upgrading.

From now on, it is recommended that if you customize an existing skin, you should rename the folder and place your skin definition in Skins.User.config.

tags: Subtext, Skins, Skinning, Blogs

comments edit

Gratuitious nature pic for no good reason other than I love Windows
WriterJust sticking my head above water long enough to take a breath and to link to some rubbish called the Programmer’s Bill of Rights that Jeff Atwood declares on his blog.

I don’t understand this guy.  You let this sort of dangerous propaganda spread and software departments will become much more efficient and be able to build better systems with less money. 

You realize what that means, don’t you?  Companies will be able to get more done with less people

For those who lose their jobs because of this, blame Atwood.  Then again, if you’re reading his blog, you’re probably not the target audience that would get laid off due to increased efficiency.  Readers of my blog on the other hand …

comments edit

This post is an ode to one of my favorite, albeit extremely minor, additions to .NET 2.0.  This is the method that I am sure we have all written in some sort of StringHelper library of some sort, but are now glad it is included in the framework as it makes our code a tad bit cleaner and shuts up that pesky FxCop warning about using the length of the string to test for empty strings.

And under the hood, it does the right thing.

public static bool IsNullOrEmpty(string value)
      if (value != null)
            return (value.Length == 0);
      return true;

If you haven’t met this method, do get well acquainted.