Is Maxtor messing with his costumers pocket?

A few days ago, my aunt ask me to buy her an external portable hard drive for backups.

She’s an accounting freelancer and works mainly in a laptop computer. To prevent loosing data she makes periodical accounting data backups.

I ask her to see the backup data size and is small … very small, so … I decide to buy her a small capacity 2,5´´ external hard drive.

Here is the chosen one: read more

ASP.NET Controls – Improving automatic ID generation : The ShortIDs Naming Provider (Part 4)

In the previous posts on this subject I wrote about why automatic ID generation should be improved and how we can improve it. Now I will step forward and show you my own implementation of a specific naming provider.

As we saw in part 3, to create a specific Naming provider you only need to develop your own implementation of SetControlID method.

I named my naming provider ShortIDsProvider and it will have only one specification to meet:

    • it will create IDs in the form Txxx

where T denotes the ‘T’ character and xxx denotes an unique incremental integer value.[more]

Why using the ‘T’ character? Well, since Control.ID must always start by an alphabetic character … I choose on my own risk the ‘T’ char.

So … here it is:

 public   class   ShortIDsProvider  :  NamingProvider
 {
     #region  Private Fields
     private   const   string  ID_PREFIX =  "T" ;
     private   static   object  KeepLongIDsAttributeValueKey =  new   object ();
     #endregion  Private Fields

     #region  Public Methods
     private   bool  KeepOriginalID(System.Web.UI. Control  control)
    {
         bool  keepOriginalIDs =  false ;

         #region  KeepLongIDs Attribute Value Management
         if  (! this .KeepOriginalIDs)
        {
             if  ( HttpContext .Current.Items.Contains(KeepLongIDsAttributeValueKey))
            {
                keepOriginalIDs = ( bool ) HttpContext .Current.Items[KeepLongIDsAttributeValueKey];
            }
             else
             {
                 string  path = System.Web. HttpContext .Current.Request.Path.Replace(System.Web. HttpContext .Current.Request.ApplicationPath,  string .Empty);

                 if  ( this .ExceptionList !=  null  &&  this .ExceptionList.Contains(path))
                {
                    keepOriginalIDs =  true ; ;
                }
                 else
                 {
                     if  (control.Page !=  null )
                    {
                         object [] atts = control.Page.GetType().GetCustomAttributes( true );

                         foreach  ( Attribute  att  in  atts)
                        {
                             if  (att  is   KeepOriginalIDsAttribute )
                            {
                                keepOriginalIDs = (( KeepOriginalIDsAttribute )att).Enabled;
                                 break ;
                            }
                        }
                    }
                }
                 HttpContext .Current.Items[KeepLongIDsAttributeValueKey] = keepOriginalIDs;
            }
        }
         #endregion  KeepLongIDs Attribute Value Management

         return  keepOriginalIDs;
    }
     #endregion  Public Methods

     #region  NamingProvider Implementation

    /// <summary>
    /// Generates the Control ID.
    /// </summary>
    /// <param name="name">The controls name.</param>
    /// <param name="control">The control.</param>
    /// <returns></returns>
    public   override   string  SetControlID( string  name, System.Web.UI. Control  control)
    {
         if  ( this .KeepOriginalID(control))
        {
             return  name;
        }
         if  (control ==  null )
        {
             throw   new   ArgumentNullException ( "control" );
        }
         if  (control.NamingContainer ==  null )
        {
             return  name;
        }
         NamingContainerControlCollection  controlsCollection = control.NamingContainer.Controls  as   NamingContainerControlCollection ;
         if  (controlsCollection ==  null )
        {
             return  name;
        }

         string  shortid =  null ;
         if  (!controlsCollection.ContainsName(name))
        {
            shortid =  string .Format( "{0}{1}" , ID_PREFIX, controlsCollection.GetUniqueControlSufix());

             if  ( string .IsNullOrEmpty(name))
            {
                name = shortid;
            }
            controlsCollection.RegisterControl(shortid, name, control);
        }
         else
         {
            shortid = control.ID;
        }
         return  shortid;
    }

     #endregion  NamingProvider Implementation
}

As you can see it’s not rocket science, and enable us to create any automatic id generation strategy.

Naturally this ShortIDsProvider is only valuable in conjugation with a set of improved web controls.

Making an improved web control is also very simple and straight forward. Here is the improved TextBox control:

 public   class   TextBox  : System.Web.UI.WebControls. TextBox
 {
     #region  Naming Management

        /// <summary>
    /// Creates a new <see cref="T:System.Web.UI.ControlCollection"></see> object to hold the child controls (both literal and server) of the server control.
    /// </summary>
    /// <returns>
    /// A <see cref="T:System.Web.UI.ControlCollection"></see> object to contain the current server control's child server controls.
    /// </returns>
     protected   override   ControlCollection  CreateControlCollection()
    {
         return   NamingConfiguration .Provider.CreateControlCollection( this );
    }

    /// <summary>
    /// Gets or sets the programmatic identifier assigned to the server control.
    /// </summary>
    /// <value></value>
    /// <returns>The programmatic identifier assigned to the control.</returns>
     public   override   string  ID
    {
         get {  return   NamingConfiguration .Provider.GetControlID( this ,  base .ID); }
         set  {  base .ID =  NamingConfiguration .Provider.SetControlID( value ,  this ); }
    }

    /// <summary>
    /// Searches the current naming container for a server control with the specified id and an integer, specified in the pathOffset parameter, which aids in the search. You should not override this version of the <see cref="Overload:System.Web.UI.Control.FindControl"></see> method.
    /// </summary>
    /// <param name="id">The identifier for the control to be found.</param>
    /// <param name="pathOffset">The number of controls up the page control hierarchy needed to reach a naming container.</param>
    /// <returns>
    /// The specified control, or null if the specified control does not exist.
    /// </returns>
     protected   override   Control  FindControl( string  id,  int  pathOffset)
    {
         Control  ctrl =  base .FindControl(id, pathOffset);
         if  (ctrl ==  null )
        {
            ctrl =  NamingConfiguration .Provider.FindControl( this , id, pathOffset);
        }
         return  ctrl;
    }

    /// <summary>
    /// Raises the <see cref="E:System.Web.UI.Control.Init"></see> event.
    /// </summary>
    /// <param name="e">An <see cref="T:System.EventArgs"></see> object that contains the event data.</param>
     protected   override   void  OnInit( EventArgs  e)
    {
         this .EnsureID();
         this .ID =  base .ID;
         base .OnInit(e);
    }
     #endregion  Naming Management

}

The last step is configuration: first to instruct asp.net to use our improved web controls instead of the usual ASP.NET controls. We do this thru TagMapping configuration, like this:

<system.web>
  <pages>
    <tagMapping>
      <add tagType="System.Web.UI.WebControls.TextBox, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
           mappedTagType="IDsSample.Controls.TextBox"/>
    </tagMapping>
  </pages>
</system.web>

 

And second, setting the default Naming provider. The web.config should look similar to this one:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="NamingConvention" type="IDsSample.Configuration.NamingSection"
          allowDefinition="MachineToApplication"
          restartOnExternalChanges="true" />

  </configSections>
  <appSettings/>
  <connectionStrings/>
  <system.web>
    <compilation debug="true"/>
    <authentication mode="Windows"/>

    <pages>
      <tagMapping>
        <add tagType="System.Web.UI.WebControls.TextBox, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
             mappedTagType="IDsSample.Controls.TextBox"/>
      </tagMapping>
    </pages>
  </system.web>

  <NamingConvention defaultProvider="ShortIDs">
    <providers>
      <add name="ShortIDs" type="IDsSample.Providers.ShortIDsProvider"
           exceptionlist="/Exception.aspx"
           keeporiginalids="false"/>
    </providers>
  </NamingConvention>

</configuration>

Please note that TagMapping will only work for controls declared in markup. If you need to create dynamic controls then use the DynamicControlBuilder class.

I’m currently working on a NunoGomesControlToolkit that can be applied to any existing web application in order to increase performance by reducing the rendered html size.

While waiting for the NunoGomesControlToolkit you can try this sample solution: ShortIDs NamingProvider Sample