Skip to main content

Event-Engine Framework, Dynamics Code Better

Hallo, I am Naveen. A full-time solution designer & developer for Microsoft applications (SAS & Custom software development). This blog post is for Dynamics CRM solutions enthusiasts, to solve one of the biggest problems in their development life cycle (Code Management). Well the solution explained in this post solve back-end code management problem only for Plugins, but sooner, I will come up with something for front-end as well.

Microsoft Dynamics CRM was originally developed for building applications that range from Sales, Marketing to Customer Service. But nowadays it's not just limited to these applications, It's being used to build a variety of applications, that include back-end system for small industry to highly scalable system of an Enterprise business.At first glance Dynamics CRM may looks a no-code solution to develop, but it's not. For developing enterprise grade solutions we have to rely on C# code to stuff all our business logic. So it's mission critical to manage all the bits & pieces of the back-end logic in a well structured manner, so that we don't have to take a roller coaster ride every time we need a small change in business logic.

Event-Engine removes most of the recurring code that includes Message name check & Stage check and provide set of methods to override for all possible combinations of Message & Stage for cleaner code approach.

Info! Sooner, I will come up with a series of blog posts on how to manage code well in C#. Follow my blog for more updates.

  • Create a Project in Visual Studio.
  • Create a folder named Internal in the project and create a new file named Controller.cs.
  • Copy and paste below code in Controller.cs file.
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SalesPlugins.Internals
{
    public class Controller
    {
        public string ControllerEntitySchemaName { get; set; }

        public void Execute(IServiceProvider serviceProvider)
        {

            if (string.IsNullOrEmpty(ControllerEntitySchemaName))
                throw new InvalidPluginExecutionException("Please define the ControllerEntitySchemaName");

            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            if (context.PrimaryEntityName != ControllerEntitySchemaName)
                throw new InvalidPluginExecutionException("EntityController is regsitered on different Entity, other than specified");

            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {
                Entity entity = (Entity)context.InputParameters["Target"];

                IOrganizationServiceFactory serviceFactory =
                    (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

                try
                {
                    if (context.MessageName == PluginMessages.Create.ToString())
                    {
                        Create(context, service, entity);
                    }
                    else if (context.MessageName == PluginMessages.Update.ToString())
                    {
                        Update(context, service, entity);
                    }
                    else
                    {
                        Default(context, service, entity);
                    }
                }
                catch (Exception ex)
                {
                    throw new InvalidPluginExecutionException(ex.Message);
                }
            }
            else if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is EntityReference)
            {
                EntityReference entityReference = (EntityReference)context.InputParameters["Target"];

                IOrganizationServiceFactory serviceFactory =
                    (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

                try
                {
                    if (context.MessageName == PluginMessages.Delete.ToString())
                    {
                        Delete(context, service, entityReference);
                    }
                    else if (context.MessageName == PluginMessages.Associate.ToString())
                    {
                        Associate(context, service, entityReference);
                    }
                    else if (context.MessageName == PluginMessages.Disassociate.ToString())
                    {
                        Disassociate(context, service, entityReference);
                    }
                    else if (context.MessageName == PluginMessages.Retrieve.ToString())
                    {
                        Retrieve(context, service, entityReference);
                    }
                    else if (context.MessageName == PluginMessages.Assign.ToString())
                    {
                        Assign(context, service, entityReference);
                    }
                    else if (context.MessageName == PluginMessages.GrantAccess.ToString())
                    {
                        GrantAccess(context, service, entityReference);
                    }
                    else if (context.MessageName == PluginMessages.RevokeAccess.ToString())
                    {
                        RevokeAccess(context, service, entityReference);
                    }
                    else if (context.MessageName == PluginMessages.ModifyAccess.ToString())
                    {
                        ModifyAccess(context, service, entityReference);
                    }
                    else
                    {
                        Default(context, service, entityReference);
                    }
                }
                catch (Exception ex)
                {
                    throw new InvalidPluginExecutionException(ex.Message);
                }
            }
            else if (context.InputParameters.Contains("Query") && context.InputParameters["Query"] is QueryExpression)
            {
                QueryExpression queryExpression = (QueryExpression)context.InputParameters["Query"];
                IOrganizationServiceFactory serviceFactory =
                    (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
                try
                {
                    if (context.MessageName == PluginMessages.RetrieveMultiple.ToString())
                    {
                        RetrieveMultiple(context, service, queryExpression);
                    }
                    else
                    {
                        throw new InvalidPluginExecutionException("The specified step is not available for this EntryPoint");
                    }
                }
                catch (Exception ex)
                {

                    throw new InvalidPluginExecutionException(ex.Message);
                }
            }
            else
            {
                IOrganizationServiceFactory serviceFactory =
                    (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

                Default(context, service);
            }
        }

        public void Create(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                CreateAction_PreValidation(context, service, entity);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                CreateAction_PreOperation(context, service, entity);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                CreateAction_PostOperation(context, service, entity);
            }
        }

        public void Delete(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                DeleteAction_PreValidation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                DeleteAction_PreOperation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                DeleteAction_PostOperation(context, service, entityReference);
            }
        }

        public void Retrieve(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                RetrieveAction_PreValidation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                RetrieveAction_PreOperation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                RetrieveAction_PostOperation(context, service, entityReference);
            }
        }

        public void RevokeAccess(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                RevokeAccessAction_PreValidation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                RevokeAccessAction_PreOperation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                RevokeAccessAction_PostOperation(context, service, entityReference);
            }
        }

        public void GrantAccess(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                GrantAccessAction_PreValidation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                GrantAccessAction_PreOperation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                GrantAccessAction_PostOperation(context, service, entityReference);
            }
        }

        public void ModifyAccess(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                ModifyAccessAction_PreValidation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                ModifyAccessAction_PreOperation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                ModifyAccessAction_PostOperation(context, service, entityReference);
            }
        }

        public void RetrieveMultiple(IPluginExecutionContext context, IOrganizationService service, QueryExpression queryExpression)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                RetrieveMultipleAction_PreValidation(context, service, queryExpression);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                RetrieveMultipleAction_PreOperation(context, service, queryExpression);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                RetrieveMultipleAction_PostOperation(context, service, queryExpression);
            }
        }

        public void Update(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                UpdateAction_PreValidation(context, service, entity);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                UpdateAction_PreOperation(context, service, entity);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                UpdateAction_PostOperation(context, service, entity);
            }
        }

        public void Associate(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                AssociateAction_PreValidation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                AssociateAction_PreOperation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                AssociateAction_PostOperation(context, service, entityReference);
            }
        }

        public void Assign(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                AssignAction_PreValidation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                AssignAction_PreOperation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                AssignAction_PostOperation(context, service, entityReference);
            }
        }

        public void Disassociate(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                AssignAction_PreValidation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                AssignAction_PreOperation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                AssignAction_PostOperation(context, service, entityReference);
            }
            DisassociateAction(context, service, entityReference);
        }

        public void Default(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                DefaultAction_PreValidation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                DefaultAction_PreOperation(context, service, entityReference);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                DefaultAction_PostOperation(context, service, entityReference);
            }

        }

        public void Default(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
            if (context.Stage == (int)PluginStage.PreValidation)
            {
                DefaultAction_PreValidation(context, service, entity);
            }
            else if (context.Stage == (int)PluginStage.PreOperation)
            {
                DefaultAction_PreOperation(context, service, entity);
            }
            else if (context.Stage == (int)PluginStage.PostOperation)
            {
                DefaultAction_PostOperation(context, service, entity);
            }
        }

        public void Default(IPluginExecutionContext context, IOrganizationService service)
        {
            DefaultAction(context, service);
        }



        public virtual void CreateAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
        }

        public virtual void CreateAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
        }

        public virtual void CreateAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
        }

        public virtual void UpdateAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
        }

        public virtual void UpdateAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
        }

        public virtual void UpdateAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
        }

        public virtual void DeleteAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void DeleteAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void DeleteAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void AssociateAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void AssociateAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void AssociateAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void DisassociateAction(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void RetrieveAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void RetrieveAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void RetrieveAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void RetrieveMultipleAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, QueryExpression queryExpression)
        {
        }

        public virtual void RetrieveMultipleAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, QueryExpression queryExpression)
        {
        }

        public virtual void RetrieveMultipleAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, QueryExpression queryExpression)
        {
        }

        public virtual void AssignAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void AssignAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void AssignAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void RevokeAccessAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void RevokeAccessAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void RevokeAccessAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void GrantAccessAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void GrantAccessAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void GrantAccessAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void ModifyAccessAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void ModifyAccessAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void ModifyAccessAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void DefaultAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void DefaultAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void DefaultAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, EntityReference entityReference)
        {
        }

        public virtual void DefaultAction_PreValidation(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
        }

        public virtual void DefaultAction_PreOperation(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
        }

        public virtual void DefaultAction_PostOperation(IPluginExecutionContext context, IOrganizationService service, Entity entity)
        {
        }

        public virtual void DefaultAction(IPluginExecutionContext context, IOrganizationService service)
        {
        }

    }

    public enum PluginStage
    {
        PreValidation = 10,
        PreOperation = 20,
        PostOperation = 40
    }

    public enum PluginMessages
    {
        Assign,
        Create,
        Delete,
        GrantAccess,
        ModifyAccess,
        Retrieve,
        RetrieveMultiple,
        RetrievePrincipalAccess,
        RetrieveSharedPrincipalsAndAccess,
        RevokeAccess,
        SetState,
        Update,
        Associate,
        Disassociate
    }

    public enum DefaultMessages
    {
        Close
    }
}

  • Add new folder named Controller in the project and start adding your plugins there.
Solution Explorer
  • If you want to create a plugin for lead, name the file LeadController.cs for uniformity.
  • Extend the Controller class & IPlugin interface in your code.
  • Just write override and you will get list of methods for all possible Messages & Stage combination.

  • Just override the method and add your logic there, no need of additional checks.
  • For out of box Messages on out of box entities, DefaultAction can be overrides, Additional check for those messages will be required to add there.
You can fork me on Git (https://github.com/ng-7015405148/Dynamics-CRM-Event-Engine) to get the latest updates for upcoming addons in the framework.

Thanks for reading. Have a nice day!




Comments

Post a Comment

Popular posts from this blog

Design Patterns for better code - Null Object Design Pattern

Null being a part of programming languages is a billion dollar mistake. -Tony Hoare Writing everyday code irrespective of Language used (either be C# or Java or Python) we write null checks. Well we write null checks so often that a study estimates on an average one developer gives 5% of his entire development time to null checks only. So we can think of the importance of null checks. It's also the main problem of production issues specially for Junior developers.  Well writing null checks is not a problem until 100 lines of code contains 20 lines of null check code 😀 To reduce the number of lines for null checks, so that developer only focus on business logic instead of null check, Null Object design pattern was invented. Let's look at how we can use Null Object Design Pattern for our Invoice Application. Here we have different types of Invoice logic written in Separate Invoice classes (EmailInvoice, PDFInvoice, SMSInvoice). The User will choose the Invoice Type at runti...