I originally thought of this idea while at Professional Edge. We had a client that wanted to build a portal and resell the functionality it provided to other companies. The main functionality and content for the site would be the same for each customer, but styles, images, and logos would change based on each company allowing the company to portray the website as their own. Professional Edge closed before the project was signed off on so I never got the chance to tackle a solution, but every once in awhile the concepts pops back into my head. I am sure this is a fairly common scenario and most likely what I have done here has been done plenty of times before, but I thought I would attempt to put together a proof of concept. My initial plan was to dynamically generate the App_Themes data based on information from the database. Using this method the developer would build the site with the look and feel defined via css tags and skin ids. The end corporate user would then have a user interface to define their custom styles and images that applied to each css tag and skin id. If the user did not define a tag then the website would simple use a default theme that the developer defined.
To do all this I have utilized the functionality of virtual path providers. A virtual path provider allows you to essentially take over when ASP.NET is looking for the file to server to the user. In my particular case it is for .css and .skin files, so that whenever a request comes in for one of these files it is instead dynamically built based on data from the database. Originally I had planned to associate a particular theme name with each portal's customizations. For example on the pre-init the theme would be dynamically set based on some type of user information, either a login account, or possibly the web address used to access the site. Basically any type of information that establishes the unique portal that the visitor is attempting to reach. Unfortunately this plan won't work. Apparently ASP.NET requires the actual physical files for a theme to exist or else it will throw an error. This was a bit of a disappointment to me as I had hoped to parse the theme name in the virtual path provider to know what dynamic data to load. Since the path is the only data passed into the virtual path provider it is the easiest and cleanest way to know what data to load. If the file trying to be loaded is ThemeABC.css I could load the styles for portal ABC and if the file trying to be loaded was ThemeXYZ.css then I could have loaded the styles for portal XYZ.
Even though this method didn't work I was able to development another method that does. I have created the file structure for the Default theme with dummy files, including Default.css and Default.skin. Every portal will essentially be using this theme as far as ASP.NET is concerned, but when a request comes in for Default.css or Default.skin I pass back a dynamically generated file. The decision for what styles and ids need to be loaded is based on a cookie that is set in the pre-init. This cookie is then read in the in the Open function of the virtual file class for the virtual path provider and based on what the cookie says a decision is made as to what styles are handed back to the client.
In the attached sample code there are two different themes that can be accessed, blue and red. Setting the cookie is handled in the Default.aspx's OnPreInit. Since this is a proof of concept the actually string is hard coded, but it could just as easily read the address that the request came in on, a user login, or user setting. Then in the virtual path provider I handle any of the requests that come in for APP_THEME/DEFAULT/. Finally in the virtual file class I read the theme name from the cookie and hand back the proper page. Since this is a proof of concept I have simply hardcoded a few values to hand back, but you could easily query the database and hand back a much more dynamically generated file.
At this point hopefully you can see the numerous possibilities this allows for. If all the ok buttons on the entire site are defined with a skin id of btnOk then you could allow the user to upload the image they want for their ok buttons and instantly all the ok buttons on the site reflect what the user has defined. If you consistently use your css tags within you site then the user could easily define custom colors, fonts, etc. for each one. This would allow the user to very easily customize the site to the look and feel that represents their company without having a developer make any changes.
Feel free to check out the sample code at the link below and make any comments or suggestions. Since it is just a proof of concept it is a little rough and not that elegant, but it displays the point.
Download the source code to the proof of concept. (VS2008 required)