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 MicrosoftCRMusing 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); } } } }
}