Click here to Skip to main content
15,892,161 members
Articles / Web Development / ASP.NET

ASP.NET Web Component for editing SQL tables

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
29 Nov 2012CPOL11 min read 43K   2.5K   24  
ASP.NET c# component for editing SQL tables with plug-in column format adapter architecture.
/*
 * Code Copyright 2012 by Bill Frisbie
 * 
 * This code is licensed under COPL license.
 * Users are free to use this code, modify it and include it in other work, including works for resale.
 * Please include this notice in the code.
 * Author provides code 'as-is', and assumes no liability for any losses whatsoever arising from its use
 * Contact author at bfrisbie@optonline.net with any questions or suggestions.
 */
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace BFCS.Data.Common
{
    /// <summary>
    /// Class with static methods to support custom table adapters for EditTable
    /// </summary>
    public class CustomAdapters
    {
        public static StringBuilder TypeList;
        /// <summary>
        /// Get a list of all custom table adapters located in the calling assembly
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// Check all types in calling assembly for CustomTableAdapterAttribute decoration
        /// If found, generate CustomAdapterInfo class entry for that type
        /// This method is called from the <see>CallingAssembly</see> property Set handler in the EditTable class
        /// Classes decorated with the attribute should implement the ITableAdapter interface and
        /// should provide a constructor conformal with the arguments to the attribute:
        /// If Modifiers argument is set, the class should provide a constructor taking arguments
        /// DbValidator validator, string ColumnName, string Modifiers
        /// If Modifiers argument is not set, the following constructor should be provided
        /// DbValidator validator, string ColumnName
        /// 
        /// If these rules are not followed, this method will throw an exception
        /// </remarks>
        public static List<CustomAdapterInfo> GetAdapters(Assembly caller)
        {
            TypeList = new StringBuilder();
            List<CustomAdapterInfo> results = new List<CustomAdapterInfo>();
            Type[] AllTypes = caller.GetTypes();        // get a list of all defined types in the calling assembly
            foreach (Type type in AllTypes)
            {
                TypeList.Append(type.FullName + "<br/>\r\n");
                MemberInfo info = (MemberInfo)type;
                object[] customAttributes = info.GetCustomAttributes(false);
                //
                // Loop through the custom attribute objects, looking for a CustomTableAdapterAttribute
                //
                foreach (object att in customAttributes)
                {
                    TypeList.Append("Custom Attribute Type: " + att.GetType().FullName);
                    if (att is CustomTableAdapterAttribute)
                    {
                        CustomTableAdapterAttribute ctAtt = (CustomTableAdapterAttribute)att;
                        results.Add(new CustomAdapterInfo(ctAtt.TableName, ctAtt.ColumnName, type, ctAtt.Modifiers));
                        break;
                    }
                }
            }
            return results;
        }
        /// <summary>
        /// Find a custom adapter in list passed in for table/column combination
        /// Instantiate using DbValidator passed in, stored parms.
        /// </summary>
        /// <param name="list">List of CustomAdapterInfo instances, as returned by GetAdapters</param>
        /// <param name="validator">DbValidator to use with constructor</param>
        /// <param name="TableName">Table name that must match CustomAdapterInfo.TableName property</param>
        /// <param name="ColumnName">Column name that must match CustomAdapterInfo.ColumnName property</param>
        /// <returns></returns>
        public static ITableAdapter GetCustomAdapter(List<CustomAdapterInfo> list, DbValidator validator, string TableName, string ColumnName)
        {
            foreach (CustomAdapterInfo info in list)
            {
                ITableAdapter adapter = info.Instance(validator, TableName, ColumnName);        // try to gen an adapter instance
                if (adapter != null)
                    return adapter;             // we have found it
            }
            return null;                // none found
        }
    }
    /// <summary>
    /// Class that encapsulates information about a custom adapter
    /// </summary>
    /// <remarks>
    /// Includes Instance method that constructs correct instance based on whether modifiers set
    /// An ITableClass should provide a constructor for its forseen use.
    /// If no modifiers are passed, the constructor should take a SQLValidator and a string representing
    /// the column name
    /// If modifiers are passed, the constructor should also include a string for the modifier value
    /// If either scenario is to be supported, both types of constructor should be provided
    /// </remarks>
    public class CustomAdapterInfo
    {
        private string m_TableName;
        private string m_ColumnName;
        private Type m_adapterType;
        private string m_Modifiers;

        public CustomAdapterInfo(string tableName, string columnName, Type adapterType, string modifiers)
        {
            m_TableName = tableName;
            m_ColumnName = columnName;
            m_Modifiers = modifiers;
            m_adapterType = adapterType;
        }
        /// <summary>
        /// Generate an instance of the referenced type with correct constructor based on arguments
        /// </summary>
        /// <param name="validator">SQLValidator to use with constructor</param>
        /// <returns>ITableAdapter cast instance from type constructor, if applicable, valid etc.
        /// null if not.</returns>
        public ITableAdapter Instance(DbValidator validator, string TableName, string ColumnName)
        {
            if (!Applies(TableName, ColumnName))
                return null;                // does not apply
            Type[] argTypes; object[] args;
            if (m_Modifiers == null)
            {
                argTypes = new Type[] { typeof(DbValidator), typeof(string) };     // use modifier-less constructor
                args = new object[] { validator, m_ColumnName };        // with these arguments
            }
            else
            {
                argTypes = new Type[] { typeof(DbValidator), typeof(string), typeof(string) }; // use constructor with modifier
                args = new object[] { validator, m_ColumnName, m_Modifiers };   // with these arguments
            }  
            ConstructorInfo info = m_adapterType.GetConstructor(argTypes);  // search for constructor
            if (info == null)
                throw new Exception(string.Format("Can't find constructor for custom adapter type '{0}'", m_adapterType.Name));
            ITableAdapter result = null;
            try
            {
                result = (ITableAdapter)info.Invoke(args);          // try to make an instance
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("Failed to instantiate custom adapter '{0}'", m_adapterType.Name), ex);
            }
            return result;
        }
        /// <summary>
        /// Determine if this entry applies to a particular combo of table name and column name
        /// </summary>
        /// <param name="TableName"></param>
        /// <param name="ColumnName"></param>
        /// <returns></returns>
        private bool Applies(string TableName, string ColumnName)
        {
            return (m_TableName == TableName && m_ColumnName == ColumnName);
        }
    }
}
/// <summary>
/// Custom adapter attribute used to decorate custom table adapter classes
/// </summary>
/// <remarks>
/// the table name and column must be declared when declaring this attribute. The Modifiers attribute
/// is optional, but if used, the class decorated must provide a constructor that accepts it as
/// the third argument; use of the value of the Modifiers attribute is up to the implementation of the
/// derived class.
/// 
/// Classes decorated with this attribute should descend from TableAdapter and implement the ITableAdapter
/// interface. See documentation of those classes in the Connection project for information about how to
/// implement required methods.
/// </remarks>
[AttributeUsage(AttributeTargets.Class)]
public class CustomTableAdapterAttribute : Attribute
{
    private string m_TableName;
    private string m_ColumnName;
    private string m_Modifiers;

    public CustomTableAdapterAttribute(string tableName, string columnName)
    {
        m_TableName = tableName;
        m_ColumnName = columnName;
        m_Modifiers = null;
    }

    public string TableName
    {
        get { return m_TableName; }
    }

    public string ColumnName
    {
        get { return m_ColumnName; }
    }

    /// <summary>
    /// Optional named parameter used to store modifiers string
    /// </summary>
    /// <remarks>
    /// Usage is dependent on constructor for adapter
    /// </remarks>
    public string Modifiers
    {
        get { return m_Modifiers; }
        set { m_Modifiers = value; }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Rovenet, Inc.
United States United States
Bill, who thinks of himself in the third person, has been programming since the dawn of time (1974) in a wide variety of hardware environments (dipswitch settings and paper tape in the beginning), languages (asm, forth, c, c++, c#, basic [visual and unvisualizable]) and industries (graphic arts, medical technology, commercial, website, mobile devices). Corporate clients include DHL, Pitney-Bowes and now-defunct medical equipment midget Q-Med. In his free time, which is all the time, he plays bluegrass guitar, body-boards the oceans of the world and bicycles through Southern California and eastern Long Island, NY.

Comments and Discussions