Welcome to MSDN Blogs Sign in | Join | Help
CRM Plug-in that exposes explicit method for each event.

Eventing framework in CRM v4.0 is designed from the ground up to be generic not just for Create,Update,Delete messages. As a result, IPlugin interface exposes only one generic Execute method. This allow CRM to support a large number of events without exploding the interface. The drawback is, this leave a considerably large gap between generic developer-focused infrastructure and specific business-oriented usage case.

However, a thin layer of wrapper can be created to wrap generic Execute and extract relevant input and output parameters. This sample covers only Create, Update, Delete, Assign, and SetState. However, some other events such as Send, Deliver, or Route can be easily added with the same pattern.

To use it, developers can create new plug-in (e.g. MyPlugin) by

  • Adding ExplicitPlugin.cs to their plug-in project.
  • Deriving MyPlugin from ExplicitPlugin.
  • Override methods that are relevant to your project

In addition to the part that expose PreCreate/PostCreate style methods, this code sample also shows how to generically access primary key of an entity inside DynamicEntity without using metadata. This can be useful when you don't have access to metadata.

I tested it on some messages so please let me know if there are some problems so I can update it.

As usual, this code is provided as-is....

MyPlugin.cs

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Sdk;

namespace MyPluginProject
{
    public class MyPlugin : ExplicitPluginBase
    {
        protected override void PreCreate(Moniker moniker, DynamicEntity entity, IPluginExecutionContext context)
        {
            CreateTask(moniker, entity, context);
        }

        protected override void PostCreate(Moniker moniker, DynamicEntity entity, IPluginExecutionContext context)
        {
            CreateTask(moniker, entity, context);
        }

        protected override void PreUpdate(Moniker moniker, DynamicEntity entity, IPluginExecutionContext context)
        {
            CreateTask(moniker, entity, context);
        }

        protected override void PostUpdate(Moniker moniker, DynamicEntity entity, IPluginExecutionContext context)
        {
            CreateTask(moniker, entity, context);
        }

        protected override void PreDelete(Moniker moniker, IPluginExecutionContext context)
        {
            CreateTask(moniker, context);
        }

        protected override void PostDelete(Moniker moniker, IPluginExecutionContext context)
        {
            CreateTask(moniker, context);
        }

        protected override void PreAssign(Moniker moniker, SecurityPrincipal assignee, IPluginExecutionContext context)
        {
            CreateTask(moniker, context);
        }

        protected override void PostAssign(Moniker moniker, SecurityPrincipal assignee, IPluginExecutionContext context)
        {
            CreateTask(moniker, context);
        }

        protected override void PreSetState(Moniker moniker, ref string state, ref int status, IPluginExecutionContext context)
        {
            CreateTask(moniker, context);
        }

        protected override void PostSetState(Moniker moniker, string state, int status, IPluginExecutionContext context)
        {
            CreateTask(moniker, context);
        }

        private void CreateTask(Moniker moniker, IPluginExecutionContext context)
        {
            CreateTask(moniker, null, context);
        }

        private void CreateTask(Moniker moniker, DynamicEntity entity, IPluginExecutionContext context)
        {
            ICrmService service = context.CreateCrmService(true);

            DynamicEntity task = new DynamicEntity("task");
            string prefix = "pre";
            if (context.Stage == MessageProcessingStage.AfterMainOperationOutsideTransaction)
            {
                prefix = "post";
            }

            Guid id = Guid.Empty;
            if (moniker != null)
            {
                id = moniker.Id;
            }

            task["subject"] = prefix + " - " + context.MessageName + " : " + id.ToString();

            if (entity != null
                && entity.Properties.Contains("firstname"))
            {
                task["description"] = entity["firstname"];
            }

            service.Create(task);
        }
    }
}

ExplicitPluginBase.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;

using Microsoft.Crm.Sdk;

namespace MyPluginProject
{
    public abstract class ExplicitPluginBase : IPlugin
    {
        public void Execute(IPluginExecutionContext context)
        {
            AdapterBase adapter = CreateConcreteAdapter(context);

            if (adapter != null)
            {
                if (context.Stage == MessageProcessingStage.BeforeMainOperationOutsideTransaction)
                {
                    adapter.ExecutePre(this, context);
                }
                else
                {
                    adapter.ExecutePost(this, context);
                }
            }
            else
            {
                ExecuteGeneric(context);
            }
        }

        private AdapterBase CreateConcreteAdapter(IPluginExecutionContext context)
        {
            switch (context.MessageName)
            {
                case MessageName.Assign:
                    return new AssignAdapter();

                case MessageName.Create:
                    return new CreateAdapter();

                case MessageName.Update:
                    return new UpdateAdapter();

                case MessageName.Delete:
                    return new DeleteAdapter();

                case MessageName.SetState:
                case MessageName.SetStateDynamicEntity:
                    return new SetStateAdapter();

                default:
                    return null;
            }
        }

        protected virtual void PreCreate(Moniker moniker, DynamicEntity entity, IPluginExecutionContext context)
        {
            ThrowNotImplementedException();
        }

        protected virtual void PostCreate(Moniker moniker, DynamicEntity entity, IPluginExecutionContext context)
        {
            ThrowNotImplementedException();
        }

        protected virtual void PreUpdate(Moniker moniker, DynamicEntity entity, IPluginExecutionContext context)
        {
            ThrowNotImplementedException();
        }

        protected virtual void PostUpdate(Moniker moniker, DynamicEntity entity, IPluginExecutionContext context)
        {
            ThrowNotImplementedException();
        }

        protected virtual void PreDelete(Moniker moniker, IPluginExecutionContext context)
        {
            ThrowNotImplementedException();
        }

        protected virtual void PostDelete(Moniker moniker, IPluginExecutionContext context)
        {
            ThrowNotImplementedException();
        }

        protected virtual void PreAssign(Moniker moniker, SecurityPrincipal assignee, IPluginExecutionContext context)
        {
            ThrowNotImplementedException();
        }

        protected virtual void PostAssign(Moniker moniker, SecurityPrincipal assignee, IPluginExecutionContext context)
        {
            ThrowNotImplementedException();
        }

        protected virtual void PreSetState(Moniker moniker, ref string state, ref int status, IPluginExecutionContext context)
        {
            ThrowNotImplementedException();
        }

        protected virtual void PostSetState(Moniker moniker, string state, int status, IPluginExecutionContext context)
        {
            ThrowNotImplementedException();
        }

        protected virtual void ExecuteGeneric(IPluginExecutionContext context)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #region Implementation details

        private void ThrowNotImplementedException()
        {
            throw new NotImplementedException();
            // throw new NotImplementedException(string.Format(CultureInfo.InvariantCulture, "{0} is not implemented.", methodName));
        }

        #endregion

        private abstract class AdapterBase
        {
            public abstract void ExecutePre(ExplicitPluginBase plugin, IPluginExecutionContext context);

            public abstract void ExecutePost(ExplicitPluginBase plugin, IPluginExecutionContext context);

            protected Moniker GetEntityMoniker(DynamicEntity entity)
            {
                foreach (Property property in entity.Properties)
                {
                    KeyProperty key = property as KeyProperty;
                    if (key != null)
                    {
                        return new Moniker(entity.Name, key.Value.Value);
                    }
                }

                return null;
            }
        }

        private sealed class CreateAdapter : AdapterBase
        {
            public override void ExecutePre(ExplicitPluginBase plugin, IPluginExecutionContext context)
            {
                DynamicEntity entity = (DynamicEntity)context.InputParameters[ParameterName.Target];

                plugin.PreCreate(GetEntityMoniker(entity), entity, context);
            }

            public override void ExecutePost(ExplicitPluginBase plugin, IPluginExecutionContext context)
            {
                DynamicEntity entity = (DynamicEntity)context.InputParameters[ParameterName.Target];

                Moniker moniker = GetEntityMoniker(entity);
                if (moniker == null)
                {
                    moniker = new Moniker(entity.Name, (Guid)context.OutputParameters[ParameterName.Id]);
                }

                plugin.PostCreate(moniker, entity, context);
            }
        }

        private sealed class UpdateAdapter : AdapterBase
        {
            public override void ExecutePre(ExplicitPluginBase plugin, IPluginExecutionContext context)
            {
                DynamicEntity entity = (DynamicEntity)context.InputParameters[ParameterName.Target];

                plugin.PreUpdate(GetEntityMoniker(entity), entity, context);
            }

            public override void ExecutePost(ExplicitPluginBase plugin, IPluginExecutionContext context)
            {
                DynamicEntity entity = (DynamicEntity)context.InputParameters[ParameterName.Target];

                plugin.PostUpdate(GetEntityMoniker(entity), entity, context);
            }
        }

        private sealed class DeleteAdapter : AdapterBase
        {
            public override void ExecutePre(ExplicitPluginBase plugin, IPluginExecutionContext context)
            {
                Moniker moniker = (Moniker)context.InputParameters[ParameterName.Target];

                plugin.PreDelete(moniker, context);
            }

            public override void ExecutePost(ExplicitPluginBase plugin, IPluginExecutionContext context)
            {
                Moniker moniker = (Moniker)context.InputParameters[ParameterName.Target];

                plugin.PostDelete(moniker, context);
            }
        }

        private sealed class AssignAdapter : AdapterBase
        {
            public override void ExecutePre(ExplicitPluginBase plugin, IPluginExecutionContext context)
            {
                Moniker moniker = (Moniker)context.InputParameters[ParameterName.Target];
                SecurityPrincipal assignee = (SecurityPrincipal)context.InputParameters[ParameterName.Assignee];

                plugin.PreAssign(moniker, assignee, context);
            }

            public override void ExecutePost(ExplicitPluginBase plugin, IPluginExecutionContext context)
            {
                Moniker moniker = (Moniker)context.InputParameters[ParameterName.Target];
                SecurityPrincipal assignee = (SecurityPrincipal)context.InputParameters[ParameterName.Assignee];

                plugin.PostAssign(moniker, assignee, context);
            }
        }

        private sealed class SetStateAdapter : AdapterBase
        {
            public override void ExecutePre(ExplicitPluginBase plugin, IPluginExecutionContext context)
            {
                Moniker moniker = (Moniker)context.InputParameters[ParameterName.EntityMoniker];
                string stateName = (string)context.InputParameters[ParameterName.State];
                int status = (int)context.InputParameters[ParameterName.Status];

                plugin.PreSetState(moniker, ref stateName, ref status, context);

                context.InputParameters[ParameterName.State] = stateName;
                context.InputParameters[ParameterName.Status] = status;
            }

            public override void ExecutePost(ExplicitPluginBase plugin, IPluginExecutionContext context)
            {
                Moniker moniker = (Moniker)context.InputParameters[ParameterName.EntityMoniker];
                string stateName = (string)context.InputParameters[ParameterName.State];
                int status = (int)context.InputParameters[ParameterName.Status];

                plugin.PostSetState(moniker, stateName, status, context);
            }
        }
    }
}

Posted: Tuesday, November 27, 2007 6:23 AM by Akezyt
Anonymous comments are disabled
Page view tracker