ASP.NET Extender Control for Expiring Content

I recently had a specific requirement to ‘expire’ some content on a web site.  There’s a million ways to do this, but my previous use of ExtenderControl in Windows Forms development sparked my interest when I noticed the Ajax toolkit supports this (mainly for client-side functionality). 


After downloading System.Web.Extensions, and about half an hour later I’d got the ‘ExpiringExtender’ Control that can be added to your ASP.NET (2.0+) page to allow content to phase in or out. 


The only down side to this approach is that your source code becomes littered with expired code like the Earth’s orbit does with old satellites!  This was therefore a quick solution to a specific problem – not an approach I’d advocate if this is a core requirement (you need a good Content Management System with built-in scheduling).


Anyway – here’s the class (chuck it into your App_Code folder if you’re using a Web Site project – as in my example).  The code’s pretty simple – just set a couple of properties (defaulting to min and max dates if not supplied) and the control’s visible property gets set appropriately.


using System;
using 
System.Web;
using 
System.Web.UI;
using 
System.Web.UI.WebControls;


namespace 
CodeBureau.WebControls
{


    
/// <summary>
    /// This control works as a simple Extender to any server or html control to allow crude time-based 
    /// show-hide functionality.  NOTE This requires the Ajax Toolkit.
    /// </summary>
    
[TargetControlType(typeof(Control))]
    
public class ExpiringExtender : ExtenderControl
    {

        
#region Private Attributes

        
private DateTime showFrom DateTime.MinValue;
        private 
DateTime showTo DateTime.MaxValue;

        #endregion

        #region
 Public Attributes

        
/// <summary>
        /// Gets or sets the show from date.  This indicates that the control should be visible from this date/time
        /// </summary>
        /// <value>The show from.</value>
        
public DateTime ShowFrom
        {
            
get return this.showFrom}
            
set this.showFrom = value; }
        }

        
/// <summary>
        /// Gets or sets the show to date.  This indicates that the control should be visible to this date/time
        /// </summary>
        /// <value>The show to.</value>
        
public DateTime ShowTo
        {
            
get return this.showTo}
            
set this.showTo = value; }
        }

        
#endregion

        #region
 Event Handlers

        
/// <summary>
        /// Raises the <see cref=”E:PreRender”/> event.
        /// </summary>
        /// <param name=”e”>The <see cref=”System.EventArgs”/> instance containing the event data.</param>
        
protected override void OnPreRender(EventArgs e)
        {
            
base.OnPreRender(e);

            
Control control FindControl(this.Page, this.TargetControlID);
            if 
(control != null)
            {
                DateTime now 
DateTime.Now;
                if 
(now < showFrom || now > showTo)
                {
                    control.Visible 
= false;
                
}
            }

        }

        
#endregion        

        
/// <summary>
        /// Gets the script descriptors.
        /// </summary>
        /// <param name=”targetControl”>The target control.</param>
        /// <returns></returns>
        
protected override System.Collections.Generic.IEnumerable<ScriptDescriptor> GetScriptDescriptors(Control targetControl)
        {
            
return null;
        
}

        
/// <summary>
        /// Gets the script references.
        /// </summary>
        /// <returns></returns>
        
protected override System.Collections.Generic.IEnumerable<ScriptReference> GetScriptReferences()
        {
            
return null;
        
}

        
/// <summary>
        /// Finds the given control (recursively).
        /// </summary>
        /// <param name=”parent”>The parent.</param>
        /// <param name=”id”>The id.</param>
        /// <returns>the control if found (else null)</returns>
        
private Control FindControl(Control parent, string id)
        {
            Control recurse
;
            if 
(parent.ID == id)
            {
                
return parent;
            
}

            
foreach (Control child in parent.Controls)
            {
                recurse 
FindControl(child, id);
                if 
(recurse != null)
                {
                    
return recurse;
                
}
            }
            
return null;
        
}

    }

}




Colorized by: CarlosAg.CodeColorizer


And to use it in a page (I’ve got it within a master page here) you just add the registration for the extender control (note the Assembly=”App_Code” – I had to google for a while to find that.


You also have to add the ScriptManager control (an Ajax requirement), then just make sure the content you want to phase in or out has runat=”server” (it should work for HTML or Server controls).


<%@ Register Assembly=”App_Code” Namespace=”Coles.WebControls”  TagPrefix=”uc1″ %>


<asp:Content ID=”Content2″ ContentPlaceHolderID=”body” Runat=”Server”>
<asp:ScriptManager id=”ScriptManager1″ runat=”server”></asp:ScriptManager>
    
<uc1:ExpiringExtender runat=”server” ID=”a” TargetControlID=”header” ShowTo=”13 March 2008 16:15:00″></uc1:ExpiringExtender>

<h1 id=”header” runat=”server”>Hey – I turn into a pumpkin at 4:15…</h1>



Colorized by: CarlosAg.CodeColorizer

ASP.NET Open Source Content Management Systems

I’m producing a site for a client at the moment, and it quickly became apparent that I’d have a number requirements that would lead me down the CMS path:



  1. Client makes direct updates to the site (with approval/preview possibilities if possible)
  2. Built-in membership, security, roles etc (why write this yourself? – I’ve got 2 kids and just don’t have the time or inclination!)
  3. Skinning capability (OK ASP.NET gives you that ‘kindof’ for free – but I throw it in anyway)
  4. CSS-driven layout (rather than tables) – This is a technical requirement for me rather than the client, but I want to make the site accessible and SEO-friendly
  5. Capability to customise  and add generic hooks to other office-based systems
  6. Quick time to market (building all the above from scratch would be ‘fun’ I’m sure, but would also take time)

To be fair to the customer I couldn’t really suggest that I do everything from scratch when there’s plenty of open source and commercial CMS’s that can do the job very well. 


I do .NET – so I’m sure there’s plenty of great CMS’s for other platforms, but I’m not about to use this as a re-skilling exercise, charging a customer for the pleasure (as I need to do some more ‘significant’ development around the site, so will be using .NET for that).


What follows is a personal view based on my requirements and my experience (rather than extensive research into each product).


DotNetNuke


This was the first one I considered as I’d had dealings with it a few years ago (a dev ‘community’ site at a previous employer).  After playing with just about every module on the planet at the time (‘cos you do), we realised we just needed a blog, so converted to Community Server as that seemed a bit less cluttered.  (BTW if you want to run .NET blog without SQL Server (like me) then DasBlog’s what you want.


Pro’s



  • Price (free)
  • Supports pretty much everything I need (open architecture, skinning, module development etc)
  • Familiar from previous use
  • Easy to use and administer – very WYSIWYG
  • Documentation’s comprehensive (if a little focused towards the high-level architectural view). 

Con’s



  • Slow (I thought I imagined this as my own dev machine’s not a ‘beast’ and it’s running SQL 2005 express, but part of this is potentially partly due to the caching mechanism (as noted on the MojoPortal site)
  • Table-driven by default (if you want your skin to be CSS-driven you’ve either got to muck around for ages finding a ‘good’ CSS skin (there’s plenty of bad/really basic ones).  This extends to the DNN standard controls, and it takes an awfully long time (using Firebug and the IE Dev toolbar) to work out why you’ve still got fixed size fonts when you’ve gone to great length in your skin to make everything sizable.  (I’m sure again the better CSS skins address this, but you there always appears to be something that gets in the way because the original DD design uses tabular layout throughout).
  • It’s written in VB.NET (OK this isn’t a ‘real’ reason, as there’s no difference – I know!  You also shouldn’t need to do much (if anything) in VB.NET if you’re a C#’er and you want to extend things – I think I’m just a bit miffed I’ve got to work with a bit of VB.NET at work at the moment :-) )
  • Not that keen on the actual logical structure, and the limited url-rewriting.  The whole anonymous tab thing out of the box.  It seems to me that DNN was designed before lots of newer features became available and it’s had to bolt them on as time’s gone by.
  • Lastly – it doesn’t feel very open source.  It’s clear that the business model has evolved to keep the output freely available whilst making money out of books, consulting and conferences (fair play to Shaun Walker – he deserves the kudos for the product).  I just feel that things went a little ‘corporate’ a while ago, which turned me off.  I bought an iRiver rather than an iPod for the same reason (too much marketing noise that turned me off, almost trying to bombard you so you don’t even consider other products, and also trying to deter competition).  There’s also many people now trying to make money out of skins (most of which aren’t terribly good) – another indicator that the ‘community’ isn’t very focused on open source development.

MojoPortal


Until a couple of days ago I’d not heard of this, but the performance discussion (above) sparked my interest.  It’s clearly got less out-of-the-box functionality and community support than DNN and is lacking more in the documentation department, but if you’re after a no fuss implementation then this might be the way to go.


Pro’s (from the site – not my experience)



  • Free and open source
  • Multi DB support (just about any DB you’d care to use)
  • Approval/workflow support (although haven’t looked into this yet)
  • Provides major functionality required
  • Skinning uses standard ASP.NET theme-based approach
  • Aligned relatively well with accessibility guidelines (CSS layout) – XHTML compliancy 

Con’s



  • Download is actually a little confusing.  You’ve got a number of zip files and you’re left to work out which one/s you need.  I downloaded a couple then reaslied I only needed the mssql release. 
  • Documentation a little lacking (although installation pretty easy once you’ve just changed a config setting). 
  • More of a ‘developer’ product – some understanding of .NET required.  This makes it more difficult for non-techy people to get it off the ground  

Jury’s still out on this one as I’ve literally installed and that’s it.  I need to get to grips with the integration and skinning support, as I want to change the default 3 pane layout and remove the left panel, so we’ll see how that goes…


Others (That I don’t know anything about)


Rainbow Portal (looks like it might be more worth a look in a year or two when there’s a bit more support


Umbraco (not all versions free)


 


So what am I going to do now?  Install MojoPortal and see if it ‘feels’ nicer than DotNetNuke.  I’m not really too worried about future support, and upgrades as I’m providing a site to a client who will run with it once I’m done (based on what it does ‘now’ – and how stable it is ‘now’).


I’ll post the results – or add to the list when I’ve come to a conclusion after some more research

Using print stylesheets with ASP.NET Themes

ASP.NET themes are great (in principle), and allow you to have lots of control on how your pages look with theme-specific skins, stylesheets, images etc.  The only thing that’s a little bit annoying is that you can’t specify (without codebehind) what media the stylesheet should apply to. 


If you add a new stylesheet to your theme folder called ‘printer.css’, ASP.NET will omit the ‘media’ attribute when it’s output to the <head> section, and it will then be subject to the normal order of precedence rules, affecting your screen output.


There may be other easy ways to do this, but W3C generally think of everything, and then the world catches up – so just use the @media rule to surround all your media-specific styles.  The easiest way to organise this is obviously in different style sheets if you’ve got a complex layout.  My simple ‘printer.css’ is below (along with the stylesheet link generated by ASP.NET). 


This simply knocks out the left nav, right side bar and the footer (all divs of course), leaving a relatively clean page for printing. 



<link href=”../App_Themes/corporate/printer.css” type=”text/css” rel=”stylesheet” />


 

Programmatically add Meta Tags to ASP.NET Master Pages using a SiteMap

I hadn’t really used SiteMaps before, but it’s a useful feature of ASP.NET 2.0 (most people using them to drive BreadCrumb controls and site navigation).


After realising there was no support for design of the sitemap (apart from the default text editor) I found a simple (and functional) SiteMap editor here.


I then realised that I needed to add meta tags for each page in the site (NOTE: this is a simple ‘content’ site, so don’t come running to me if you have the need to generate specific tags based on what colour trousers the user is wearing!).


You can add new attributes very easily to the sitemap, and access them programmatically.  The editor has a nice little grid to make this extra easy for you.  In my example here we’ve added a ‘keywords’ attribute. 


Assuming you’re using a treeview (or something similar) for navigation on your site and you’re binding to the SiteMap data source, then you’ll get the context of the current site map node in your page (or master page).


You can then use it to set your meta tags as follows:



You can also set Page.Title from currNode.Title etc.


This is actually quite a neat way to drive things like other standard properties of your master page – e.g. subheadings.