Click here to Skip to main content
15,886,258 members
Articles / Programming Languages / C#

Task Plug-in: A Flexible .NET Plug-in Architecture

Rate me:
Please Sign up or sign in to vote.
4.75/5 (17 votes)
12 Jun 20076 min read 103.1K   2.6K   159  
The Task Plug-in library is a set of classes, interfaces, enumerations and attributes that collectively support the ITaskPlugin interface. The ITaskPlugin interface is a .NET interface created to demonstrate how to create a “Plug-in” architecture utilizing the Microsoft .NET Framework.
using System;
using System.Configuration;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Guadagno.Utilities;

using Schedule;

namespace TaskPluginInterface
{

    /// <summary>
    /// Helper functions for reading the Schedule from the Configuration file and
    /// parsing it into its correct IScheduleItem
    /// </summary>
    public static class ScheduleConfig
    {
        
        #region NodeNames Class

        /// <summary>
        /// Contains a list of all of the node names that the schedule config can contain.
        /// </summary>
        public static class NodeNames
        {
            /// <summary>
            /// The string representative of the Schedule node.
            /// </summary>
            public const string Schedule = "Schedule";
            /// <summary>
            /// The string representative of the ScheduledTime node.
            /// </summary>
            public const string ScheduledTime = "ScheduledTime";
            /// <summary>
            /// The string representative of the SimpleInterval node.
            /// </summary>
            public const string SimpleInterval = "SimpleInterval";
            /// <summary>
            /// The string representative of the SingleEvent node.
            /// </summary>
            public const string SingleEvent = "SingleEvent";
            /// <summary>
            /// The string representative of the BlockWrapper node.
            /// </summary>
            public const string BlockWrapper = "BlockWrapper";
            /// <summary>
            /// The string representative of the EventQueue node.
            /// </summary>
            public const string EventQueue = "EventQueue";
        }
        #endregion NodeNames Class

        #region NodeAttributes Class
        /// <summary>
        /// Represents the Node Attributes that are available
        /// </summary>
        public static class NodeAttributes
        {
            /// <summary>
            /// The string representative of the Base attribute.
            /// </summary>
            public const string Base = "Base";
            /// <summary>
            /// The string representative of the Offset attribute.
            /// </summary>
            public const string Offset = "Offset";
            /// <summary>
            /// The string representative of the StartTime attribute.
            /// </summary>
            public const string StartTime = "StartTime";
            /// <summary>
            /// The string representative of the Interval attribute.
            /// </summary>
            public const string Interval = "Interval";
            /// <summary>
            /// The string representative of the EndTime attribute.
            /// </summary>
            public const string EndTime = "EndTime";
            /// <summary>
            /// The string representative of the Count attribute.
            /// </summary>
            public const string Count = "Count";
            /// <summary>
            /// The string representative of the EventTime attribute.
            /// </summary>
            public const string EventTime = "EventTime";
            /// <summary>
            /// The string representative of the IScheduleItem attribute.
            /// </summary>
            public const string IScheduleItem = "IScheduleItem";
            /// <summary>
            /// The string representative of the BeginOffset attribute.
            /// </summary>
            public const string BeginOffset = "BeginOffset";
            /// <summary>
            /// The string representative of the EndOffset attribute.
            /// </summary>
            public const string EndOffset = "EndOffset";

        }
        #endregion NodeAttributes Class

        #region Private Variables

        private static log4net.ILog m_Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        #endregion Private Variables

        #region Public Constants

        #endregion Public Constants

        #region Load
        /// <summary>
        /// Loads the schedule configuration from the passed XML configuration section
        /// </summary>
        /// <param name="configSection">A configuration section to parse</param>
        /// <returns>A List&lt;IScheduledItem&gt; items</returns>
        /// <exception cref="ConfigurationErrorsException" />
        public static List<IScheduledItem> Load(string configSection)
        {
            m_Log.Debug(Properties.Resources.Msg_ScheduleConfig_Load);
            
            List<IScheduledItem> listSchedule = new List<IScheduledItem>();

            if (string.IsNullOrEmpty(configSection)) return listSchedule;

            try
            {
                XmlDocument xml = new XmlDocument();
                xml.LoadXml(configSection);

                m_Log.Debug(Properties.Resources.Msg_ScheduleConfig_Load_SelectNode);
                XmlNode schedule = xml.SelectSingleNode(NodeNames.Schedule);

                m_Log.DebugFormat(Properties.Resources.Msg_ScheduleConfig_Load_FoundCount, schedule.ChildNodes.Count);
                foreach (XmlNode node in schedule.ChildNodes)
                {
                    m_Log.DebugFormat(Properties.Resources.Msg_ScheduleConfig_Load_NodeType, node.Name);
                    switch (node.Name)
                    {
                        case NodeNames.ScheduledTime:
                            listSchedule.Add(GetScheduledTime(node));
                            break;

                        case NodeNames.SimpleInterval:
                            listSchedule.Add(GetSimpleInterval(node));
                            break;

                        case NodeNames.SingleEvent:
                            listSchedule.Add(GetSingleEvent(node));
                            break;

                        case NodeNames.BlockWrapper:
                            listSchedule.Add(GetBlockWrapper(node));
                            break;

                        case NodeNames.EventQueue:
                            listSchedule.Add(GetEventQueue(node));
                            break;

                    }
                }

            }
            catch (Exception ex)
            {
                m_Log.Error(Properties.Resources.Msg_ScheduleConfig_Load_Exception, ex);
                throw new ConfigurationErrorsException(Properties.Resources.Msg_ScheduleConfig_Load_Exception, ex);
            }

            return listSchedule;
        }
        #endregion Load

        #region IScheduleTime Types

        #region GetScheduledTime
        /// <summary>
        /// Reads the XmlNode and returns a ScheduledTime
        /// </summary>
        /// <param name="node">The ScheduledTime XML Node</param>
        /// <returns>A ScheduledTime</returns>
        /// <remarks>
        /// There is one valid attribute combination available for a ScheduledTime object.<br></br>
        /// The Node must have a <b>Base</b> and <b>Offset</b> attribute.<br></br>
        /// <example>&lt;ScheduledTime Base="" Offset="" /&gt;</example>
        /// </remarks>
        public static ScheduledTime GetScheduledTime(XmlNode node)
        {
            m_Log.DebugFormat(Properties.Resources.Msg_ScheduleConfig_Load_Node, NodeNames.ScheduledTime);
            
            // Options Available
            // Base, Offset

            string sBase;
            string sOffset;

            sBase = node.Attributes[NodeAttributes.Base].Value;
            sOffset = node.Attributes[NodeAttributes.Offset].Value;

            if (sBase == null) throw new ConfigurationErrorsException(string.Format(Properties.Resources.Msg_ScheduleConfig_Ex_MissingAttribute, NodeAttributes.Base, NodeNames.ScheduledTime), node);
            if (sOffset == null) throw new ConfigurationErrorsException(string.Format(Properties.Resources.Msg_ScheduleConfig_Ex_MissingAttribute, NodeAttributes.Offset, NodeNames.ScheduledTime), node);

            return new ScheduledTime(sBase, sOffset);
        }
        #endregion GetScheduledTime

        #region GetSimpleInterval

        /// <summary>
        /// Reads the XmlNode and returns a SimpleInterval
        /// </summary>
        /// <param name="node">The SimpleInterval XmlNode to parse.</param>
        /// <returns>A SimpleInterval</returns>
        /// <remarks>
        /// There are three available combinations for the SimpleInterval node.<br></br>
        /// StartTime, Interval, EndTime<br></br>
        /// StartTime, Interval<br></br>
        /// StartTime, Interval, Count<br></br>
        /// </remarks>
        /// <example>
        /// &lt;SimpleInterval <b>StartTime</b>="" <b>Interval</b>="" <b>EndTime</b>="" /&gt;<br></br> 
        /// &lt;SimpleInterval <b>StartTime</b>="" <b>Interval</b>="" /&gt;<br></br> 
        /// &lt;SimpleInterval <b>StartTime</b>="" <b>Interval</b>="" <b>Count</b>="" /&gt;<br></br> 
        /// </example>
        public static SimpleInterval GetSimpleInterval(XmlNode node)
        {
            m_Log.DebugFormat(Properties.Resources.Msg_ScheduleConfig_Load_Node, NodeNames.SimpleInterval);

            // Options Available for SimpleInterval
            // StartTime, Interval, EndTime
            // StartTime, Interval
            // StartTime, Interval, Count

            DateTime? startTime = null;
            DateTime? endTime = null;
            TimeSpan? interval = null;
            int? count = null;

            if (node.Attributes[ NodeAttributes.StartTime] != null) { TryParse.TryNullableDateTime(node.Attributes["StartTime"].Value, out startTime); }

            if (node.Attributes[ NodeAttributes.Interval] != null) { TryParse.TryNullableTimeSpan(node.Attributes["Interval"].Value, out interval); }

            if (node.Attributes[ NodeAttributes.EndTime] != null) { TryParse.TryNullableDateTime(node.Attributes["EndTime"].Value, out endTime); }

            if (node.Attributes[ NodeAttributes.Count] != null) { TryParse.TryNullableInt(node.Attributes["Count"].Value, out count); }

            // Determine which Constructor to call
            // StartTime and Interval are required

            if (startTime == null) throw new ConfigurationErrorsException(string.Format(Properties.Resources.Msg_ScheduleConfig_Ex_MissingAttribute, NodeAttributes.StartTime, NodeNames.SimpleInterval), node);
            if (interval == null) throw new ConfigurationErrorsException(string.Format(Properties.Resources.Msg_ScheduleConfig_Ex_MissingAttribute, NodeAttributes.Interval, NodeNames.SimpleInterval), node);

            if (endTime != null)
            {
                return new SimpleInterval(startTime.Value, interval.Value, endTime.Value);
            }
            if (count != null)
            {
                return new SimpleInterval(startTime.Value, interval.Value, count.Value);
            }

            // The default
            return new SimpleInterval(startTime.Value, interval.Value);

        }

        #endregion GetSimpleInterval

        #region GetSingleEvent
        /// <summary>
        /// Read the XmlNode and returns a SingleEvent
        /// </summary>
        /// <param name="node">The SingleEvent XmlNode to parse.</param>
        /// <returns>A SingleEvent</returns>
        /// <remarks>There is one available option for the SingleEvent node.</remarks>
        /// <example>&lt;SingleEvent <b>EventTime</b>=""&gt;</example>
        public static SingleEvent GetSingleEvent(XmlNode node)
        {
            m_Log.DebugFormat(Properties.Resources.Msg_ScheduleConfig_Load_Node, NodeNames.SingleEvent);

            // Options Available
            // EventTime

            DateTime? eventTime = null;

            if (node.Attributes[ NodeAttributes.EventTime] != null) { TryParse.TryNullableDateTime(node.Attributes["EventTime"].Value, out eventTime); }
            if (eventTime != null)
            {
                return new SingleEvent(eventTime.Value);
            }
            else
            {
                throw new ConfigurationErrorsException(string.Format(Properties.Resources.Msg_ScheduleConfig_Ex_MissingAttribute, NodeAttributes.EventTime, NodeNames.SingleEvent), node);
            }

        }

        #endregion GetSingleEvent

        #region GetBlockWrapper
        /// <summary>
        /// Reads the XmlNode and returns a SimpleInterval
        /// </summary>
        /// <param name="node">The BlockWrapper XmlNode</param>
        /// <returns>A BlockWrapper</returns>
        /// <remarks>
        /// The Blockwrapper requires a Base, BeginOffset and EndOffset attributes and a Child node of an IScheduledItem
        /// </remarks>
        /// <example>
        /// &lt;BlockWrapper <b>Base</b>="" <b>BeginOffset</b>="" <b>EndOffset</b>&gt;<br></br>
        ///   &lt;SimpleInterval <b>StartTime</b>="" <b>Interval</b>="" <b>EndTime</b>="" /&gt;<br></br> 
        /// &lt;BlockWrapper&gt;
        /// </example>
        public static BlockWrapper GetBlockWrapper(XmlNode node)
        {
            m_Log.DebugFormat(Properties.Resources.Msg_ScheduleConfig_Load_Node, NodeNames.BlockWrapper);

            // Options Available
            // IScheduleItem, Base, BeginOffset, EndOffset

            string sBase, beginOffset, endOffset;
            IScheduledItem scheduledItem = null;

            sBase = node.Attributes[NodeAttributes.Base].Value;
            beginOffset = node.Attributes[ NodeAttributes.BeginOffset].Value;
            endOffset = node.Attributes[ NodeAttributes.EndOffset].Value;

            if (sBase == null) throw new ConfigurationErrorsException(string.Format(Properties.Resources.Msg_ScheduleConfig_Ex_MissingAttribute,  NodeAttributes.Base, NodeNames.BlockWrapper), node);
            if (beginOffset == null) throw new ConfigurationErrorsException(string.Format(Properties.Resources.Msg_ScheduleConfig_Ex_MissingAttribute, NodeAttributes.BeginOffset, NodeNames.BlockWrapper), node);
            if (endOffset == null) throw new ConfigurationErrorsException(string.Format(Properties.Resources.Msg_ScheduleConfig_Ex_MissingAttribute, NodeAttributes.EndOffset, NodeNames.BlockWrapper), node);

            XmlNode scheduleNode = node.FirstChild;

            if (scheduleNode == null) throw new ConfigurationErrorsException(string.Format(Properties.Resources.Msg_ScheduleConfig_Ex_MissingAttribute, NodeAttributes.IScheduleItem, NodeNames.BlockWrapper), node);

            m_Log.DebugFormat(Properties.Resources.Msg_ScheduleConfig_Load_Node, scheduleNode.Name);
            switch (scheduleNode.Name)
            {
                case NodeNames.ScheduledTime:
                    scheduledItem = GetScheduledTime(scheduleNode);
                    break;

                case NodeNames.SimpleInterval:
                    scheduledItem = GetSimpleInterval(scheduleNode);
                    break;

                case NodeNames.SingleEvent:
                    scheduledItem = GetSingleEvent(scheduleNode);
                    break;

            }

            return new BlockWrapper(scheduledItem, sBase, beginOffset, endOffset);
        }

        #endregion GetBlockWrapper

        #region GetEventQueue
        /// <summary>
        /// Reads the XmlNode and returns an EventQueue
        /// </summary>
        /// <param name="node">The EventQueue node to parse</param>
        /// <returns>An EventQueue</returns>
        /// <remarks>
        /// The EventQueue contains one or more IScheduleItems
        /// </remarks>
        /// <example>
        /// &lt;EventQueue&gt; <br></br>
        ///     &lt;SimpleInterval <b>StartTime</b>="" <b>Interval</b>="" <b>EndTime</b>="" /&gt;<br></br> 
        ///     &lt;SimpleInterval <b>StartTime</b>="" <b>Interval</b>="" /&gt;<br></br> 
        ///     &lt;SimpleInterval <b>StartTime</b>="" <b>Interval</b>="" <b>Count</b>="" /&gt;<br></br> 
        /// &lt;/EventQueue&gt;
        /// </example>
        public static EventQueue GetEventQueue(XmlNode node)
        {
            m_Log.DebugFormat(Properties.Resources.Msg_ScheduleConfig_Load_Node, NodeNames.EventQueue);

            EventQueue queue = new EventQueue();

            if (node.ChildNodes.Count == 0) throw new ConfigurationErrorsException(string.Format(Properties.Resources.Msg_ScheduleConfig_Ex_MissingAttribute, NodeAttributes.IScheduleItem, NodeNames.EventQueue), node);

            foreach (XmlNode child in node.ChildNodes)
            {
                m_Log.DebugFormat(Properties.Resources.Msg_ScheduleConfig_Load_Node, child.Name);
                switch (child.Name)
                {
                    case NodeNames.ScheduledTime:
                        queue.Add(GetScheduledTime(child));
                        break;

                    case NodeNames.SimpleInterval:
                        queue.Add(GetSimpleInterval(child));
                        break;

                    case NodeNames.SingleEvent:
                        queue.Add(GetSingleEvent(child));
                        break;

                    case NodeNames.BlockWrapper:
                        queue.Add(GetBlockWrapper(child));
                        break;

                    case NodeNames.EventQueue:
                        queue.Add(GetEventQueue(child));
                        break;
                }
            }

            return queue;
        }
        #endregion GetEventQueue

        #endregion IScheduleTime Types

        #region Helper Functions

        #endregion Helper Functions

    }
}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
I have been in software development for about 15 years or so. I started out with a small book on QuickBASIC, then moved the Visual Basic for DOS, then Visual Basic for Windows, then Visual Basic .NET and eventually Visual C#. When I am not working at my full time job I donate my time to several community efforts like:

Former President of INETA North America, currently Vice President.
President of the Southeast Valley .NET User Group (SEVDNUG) in Chandler, AZ.
Serving on my City's Parks and Recreation board.

I have or have had the following "MVP" awards:

  • Visual Basic MVP in 1996
  • C# MVP since 2009
  • Telerik MVP since 2010

I maintain a Open Source project on CodePlex which wraps the Bing API called BingSharp.

I also help / organize or participate in several community events:

  • Desert Code Camp
  • AZGiveCamp
  • Organizer for the 1st Time MVP event at the MVP Summit
  • MVP 2 MVP Sessions at MVP Summit.
  • Awesome bean pusher at GeekGive at the MVP Summit.

Comments and Discussions