home » articles » Plugin architecture made easy

Plugin architecture made easy

change text size: A A A

3/10/2009 by ajaymeher

Overview
========

Plugin architecture is kept simple in its underlying architecture. It has one main consumer and multiple providers. Providers register themselves with the Consumer and then Consumer invokes features of each providers through a common interface.

Solution
========

Lets have a problem requiring a plugin-based solution. There should be a CRM Host and it should invoke multiple external crms, here we will consider for the sake of brevity - Microsoft CRM and SalesForce ,exposing there features like loading leads, saving etc.
I am giving the details of interfaces and concrete classes below for the HOST and PLUGINS:

Interface: ICRMPlugin.cs
------------------------

using System.Collections.Generic;
using System.Collections.Specialized;

namespace CRMManagement
{
    /// <summary>
    /// Plugin interface
    /// </summary>
    public interface ICRMPlugin
    {
        ICRMPluginHost Host
        {
            get;
            set;
        }
       
        void Initialize(ICRMConfigContext crmConfig);
       
        NameValueCollection LoadLead(NameValueCollection queryValues,
            CRMQueryFilterOptions filterOptions,CRMQueryResultsOptions resultOptions,
            CRMQueryOperatorOptions interQueryOperatorOptions);

        void SaveLead(IDictionary<string, string> queryValues, IDictionary<string, string> saveValues);
    }
}


Interface: ICRMPluginHost.cs

----------------------------

namespace CRMManagement
{
    public interface ICRMPluginHost
    {
        bool Register(ICRMPlugin ipi);

        void LoadCRMPlugins();
    }
}


Concrete Host: CRMManager.cs
----------------------------

namespace CRMManagement
{
    public class CRMManager : ICRMPluginHost
    {
    ICRMPlugin[]  crmPlugins;

    public CRMManager()
    {
        string path = Application.StartupPath;
            string[] pluginFileNames = Directory.GetFiles(Path.Combine(path,"CRMs\\"), "*.dll");
            crmPlugins = new ICRMPlugin[pluginFiles.Length];

            for (int i = 0; i < pluginFiles.Length; i++)
            {
                string args = pluginFiles[i].Substring(
                    pluginFiles[i].LastIndexOf("\\") + 1,
                    pluginFiles[i].IndexOf(".dll") -
                    pluginFiles[i].LastIndexOf("\\") - 1);

                Type ObjType = null;
               
        // load the dll
                Assembly assem = Assembly.Load(args);
                if (assem != null)
                {
                    ObjType = assem.GetType(args + ".CRMPlugin");
                }

                if (ObjType != null)
                {
                   crmPlugins[i] = (ICRMPlugin)Activator.CreateInstance(ObjType);
                   crmPlugins[i].Host = this;
                }
         }   
    }

    public bool Register(ICRMPlugin ip)
        {
            //Set your custom behaviour to show all the plugins which are available to this project
        //For eg. you can have
        }

        private void LoadCRMPlugins()
        {

            foreach (ICRMPlugin plugin in crmPlugins)
            {
               if (plugin.Name.Equals("Microsoft"))
               {
        //Fetch following configs from portal
            private string crmurlConfig = "http://winserver2003:5555/mscrmservices/2007/crmservice.asmx";
            private string orgNameConfig = "ccclogic";
            private string usernameConfig = "Administrator";
            private string passwordConfig = "ccclogic";
            private string authenticationtypeConfig = "1";

                 plugin.Initialize(crmurlConfig ,orgNameConfig,usernameConfig,passwordConfig,authenticationtypeConfig);                       
               }
            }
        }

    }
}

 

Plugin Sample File: MicrosoftCRM.cs (This will be in different project and the dlls copied to the main assembly's bin folder using Post Build Events)
-----------------------------------------------------------------------------------------------------------------------------------------------------

//Add you regular assemblies here, I am just mentioning assemblies used by MicrosoftCRM
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Query;
using Microsoft.Crm;
using Microsoft.Crm.SdkTypeProxy;

namespace WebAstra.Application.CRM.MicrosoftCRM
{
    public class CRMPlugin : ICRMPlugin
    {
        private string crmurlConfig = string.Empty;//"http://<servername>:<port>/mscrmservices/2007/crmservice.asmx";
        private string orgNameConfig = string.Empty;
        private string usernameConfig = string.Empty;
        private string passwordConfig = string.Empty;
        private string authenticationtypeConfig = string.Empty;

        //ToDo: Offline handling of CRM services

        private CrmService m_crmservice;
        private string m_strName;
        private ICRMPluginHost m_Host;

        public CRMPlugin()
        {
             m_strName = "Microsoft";
        }

        public void Initialize(string m_crmurl,string m_orgName,string m_username,string m_password,string m_authenticationtype )
        {
            configContext = crmConfig;

            crmurlConfig = m_crmurl;
            orgNameConfig = m_orgName;
            usernameConfig = m_username;
            passwordConfig = m_password;
            authenticationtypeConfig = m_authenticationtype;

            // Set up the CRM Service.
            CrmAuthenticationToken token = new CrmAuthenticationToken();
            token.AuthenticationType = 0;

            int authType;
            bool bValidAuthType = int.TryParse(authenticationtypeConfig, out authType);

            if (bValidAuthType)
            {
                token.AuthenticationType = authType;
            }

            token.OrganizationName = orgNameConfig;

            m_crmservice = new CrmService();
            m_crmservice.Url = crmurlConfig;
            m_crmservice.CrmAuthenticationTokenValue = token;
            m_crmservice.Credentials = new System.Net.NetworkCredential(usernameConfig, passwordConfig, orgNameConfig);
        }

        public CrmService CRMService
        {
            get
            {
                return m_crmservice;
            }
        }

        public string Name
        {
            get
            {
                return m_strName;
            }
            set
            {
                m_strName = value;
            }
        }

        public NameValueCollection LoadLead(NameValueCollection queryValues)
        {
            //List<NameValueCollection> arrayResultValues = new List<NameValueCollection>();
            NameValueCollection resultValues = new NameValueCollection();

            //Fetch columns collection from portal config here
            List<string> columns = new List<string>();

            columns.Add("fullName");
            columns.Add("contactid");


            // Create the ColumnSet that indicates the properties to be retrieved.
            ColumnSet cols = new ColumnSet();

            // Set the properties of the ColumnSet.
            cols.Attributes.AddRange(columns);

            // Create the ConditionExpression.
            ConditionExpression condition = new ConditionExpression();

            // Create the FilterExpression.
            FilterExpression topFilter = new FilterExpression();

            foreach (string key in queryValues.Keys)
            {
                condition = new ConditionExpression();

                string queryValue = queryValues[key];

                // Set the condition for the retrieval to be when the contact's address' city is Sammamish.
                //condition.AttributeName = "address1_city";
                //condition.Operator = ConditionOperator.Like;
                //condition.Values = new string[] { "Sammamish" };

                condition.AttributeName = key;
                condition.Operator = conditionOperator;
                condition.Values = new string[] { queryValue };

                FilterExpression childFilter = new FilterExpression();

                // Set the properties of the filter.
                childFilter.FilterOperator = logicalOperator;
                childFilter.Conditions.Add(condition);

                topFilter.Filters.Add(childFilter);
            }

            // Create the QueryExpression object.
            QueryExpression query = new QueryExpression();

            // Set the properties of the QueryExpression object.
            query.EntityName = EntityName.contact.ToString();
            query.ColumnSet = cols;
            query.Criteria = topFilter;

            // Retrieve the contacts.
            BusinessEntityCollection contacts = m_crmservice.RetrieveMultiple(query);


            if (contacts != null &&
                contacts.BusinessEntities != null &&
                contacts.BusinessEntities.Count > 0)
            {
                BusinessEntity be = contacts.BusinessEntities[0];
                contact cont = (contact)be;

                try
                {
                    Type t = cont.GetType();
                    object[] indexer = new object[0];
                    PropertyInfo[] pi = t.GetProperties();
                    foreach (PropertyInfo p in pi)
                    {
                        object oContVal = p.GetValue(cont, indexer);

                        if (oContVal != null && cols.Attributes.Contains(p.Name))
                        {
                            if (oContVal is Microsoft.Crm.Sdk.Key)
                            {
                                resultValues.Add(p.Name, ((Microsoft.Crm.Sdk.Key)oContVal).Value.ToString());
                            }
                            else
                            {
                                resultValues.Add(p.Name, oContVal.ToString());
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                }
            }

            return resultValues;
        }


        public void SaveLead(IDictionary<string, string> queryValues, IDictionary<string, string> saveValues)
        {
       //Add your custom save lead logic here using the connection parameters in m_crmservice as specified in LoadLeads() API above.
        }

        public ICRMPluginHost Host
        {
            get
            {
                return m_Host;
            }
            set
            {
                m_Host = value;
                m_Host.Register(this);
            }
        }
    }

 

}

 

To rate this article please register or login

Author

ajaymeher ajaymeher (Member since:1/1/2009)

Comments (no comments yet)

Post a comment

Comment (No HTML)  

Type the characters:
 *
 
   

Related articles

Join CodeAsp.Net for FREE Today!

It's fast, easy and free! Submit articles, get your own blog, ask questions & give answers in the forums, and become a better developer, faster.

enter your email address:

Latest Articles RSS Feed

Latest Articles

  • Hi Friends, Many times we came cross the requirement when we need to access the dropdownlist's selectedindexchanged event inside the gridview, like in a shopping cart changing the item's quantity or binding the other dropdown based on the first dropdown.
  • This is the approach that I have adopted to develop Expandable / Collapsible Panel Control through JavaScript. Please report bugs, errors and suggestions to improve this control.
  • This is my approach to develop custom JavaScript ListBox control. Although it is only a subset of existing HTML ListBox element, it is more user friendly than the existing one. It can be further customized for different requirements. Please let me know about bugs and/or errors & give suggestions to improve this ListBox control.
  • I have tried my best to make this user control code error free. I will most welcome suggestions for further improvement in this user control. I have tested this user control on various browsers and it works fine.
  • So, this is my approach to implement an ASP.NET slide show using the DataList. I have tried my best to keep it bug free. I will most welcome suggestions and criticism for further improvements of this user control. I have tested this user control on various browsers and it works fine.
  • As we all knows that Repeater and DataList does not have auto paging support technique like Gridview or Datagrid, but we can achieve this through PagedDataSource. By using PagedDataSource we can implement paging in Repeater or DataList. Now in our mind there is question arise what is PagedDataSource. PagedDataSource is a class which encapsulates
  • So this is my approach. I was working for a long time to create C# like event handlers for JavaScript classes and finally, I’ve done it. Please let me know of any bugs and suggestions to improve this context menu control.
  • So this is my solution. If you have some other ideas about this functionality, please share them with me.
  • I have tried my best to make this code error free. Suggestions and criticism for further improvements of this code are most welcome.
  • So this is the approach that I've adopted to solve the Hover Delay problem. Although originally I developed Hover Delay to deactivate the click event for 1 second on a GridView row, later I also used Hover Delay to deactivate Drag n Drop of GridView rows. Kindly let me know if any one has some other better or different solution.
  • In this article I will explain how to import data from EXCEL to SQL in ASP.NET . In many situations we have data in the form of excel sheet but we have the requirement to have that data in SQL SERVER DB. I have explained importing data both from Excel 97-2003 as well as Excel 2007 format.
  • The source code shows how to use Regular Expressions in C#. The code Functions written for Validation Alphabet, AlphaNumeric, Integer, Postive Integer, Floating point numbers. You just cut copy these functions and use in any program.
  • That’s all about this technique. Just download the sample application and happy CSS! I have tested this application on various browsers and it worked fine.
  • This script is cross-browser compatible and fast as it iterates elements of a specific tag inside a target element [GridView] rather than iterating in a whole form. It searches the elements of a specific type in a particular column of the target element [GridView].
  • This Article is used to insert a numeric value on the sever control(text box) This is a java script code for the the client side validation. On Page Load Event You can change the events in txtNoOfQuestion.Attributes.Add("onkeypress", "return numericOnly(this);"); like onfocus events like other according to needs.
  • I have toggled visibility of all TD elements of a GridView column in order to create an illusion of smooth dynamic effect with the help of setTimeout method through recursion. Different browsers have different effects of Expanding / Collapsing GridView Columns. In Internet Explorer 7/8, Safari, Google Chrome and Opera, it seems that columns are Exp
  • In this article, I've used the setTimeout method in order to achieve a smooth expand/collapse functionality.
  • Introduction I am going to present here a functionality that selects / deselects all checkboxes of a particular column inside a GridView control, provided the header checkbox of that column is checked or unchecked using JavaScript. This functionality also has a feature that when all checkboxes of a particular column inside the GridView are check
  • This article describes how to toggle the states of all CheckBoxes inside a particular DataGridView column.
  • This article describes how to apply client-side mouse over & mouse out effects on the GridView’s rows.