Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Abstract classes for plugins and workflows

I have created the two following abstract classes that I use in my plugins and workflows:

/// <summary>
/// Base plugin class. Provides access to most often used Xrm resources.
/// </summary>
public abstract class BasePlugin : IPlugin
{

    public IServiceProvider ServiceProvider { get; set; }
    public ITracingService TracingService { get; set; }
    public IPluginExecutionContext PluginContext { get; set; }
    public IOrganizationService Service { get; set; }

    public void Execute(IServiceProvider serviceProvider)
    {
        ServiceProvider = serviceProvider;
        TracingService =
            (ITracingService)serviceProvider.GetService(typeof(ITracingService));

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

        IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        Service = serviceFactory.CreateOrganizationService(PluginContext.UserId);

        ExecutePluginLogic();
    }

    public virtual void ExecutePluginLogic()
    {
        throw new NotImplementedException();
    }
}

And

/// <summary>
/// Base workflow class. Provides access to most often used Xrm resources.
/// </summary>
public abstract class BaseWorkflow : CodeActivity
{
    public CodeActivityContext CodeActivityContext { get; set; }
    public IWorkflowContext WorkflowContext { get; set; }
    public ITracingService TracingService { get; set; }
    public IOrganizationService Service { get; set; }

    protected override void Execute(CodeActivityContext context)
    {
        IOrganizationServiceFactory serviceFactory = context.GetExtension<IOrganizationServiceFactory>();
        CodeActivityContext = context;
        TracingService = context.GetExtension<ITracingService>();
        WorkflowContext = context.GetExtension<IWorkflowContext>();
        Service = serviceFactory.CreateOrganizationService(WorkflowContext.UserId);

        ExecuteWorkflowLogic();
    }

    public virtual void ExecuteWorkflowLogic()
    {
        throw new NotImplementedException();
    }     
}

Here's how I would create a plugin then:

public class CalculateTaxesOnUpdate : BasePlugin
{

    public override void ExecutePluginLogic()
    {
        //From there I don't need to instanciate anything...neat!
    }
}

This seems to work fine and helps to reduce boiler plate code when it comes to initiating instances of IOrganizationService and ITracingService namely.

But I've noticed that on some messages (ie: Update of invoicedetail) that are triggered with short delays, on the first execution, public properties of BasePlugin are null (which is expected) then on the following executions, they are already initiated (??). I noticed this being an issue because I had a Dispose method in the base classes which would set properties to null after executing ExecutePluginLogic and other threads would then try to use null properties.

Since I'm not reusing them and re-initiating them anyways (which is what happens when you instanciate everything in Execute anyways), I don't know if that's an issue, but am I going against best practices here ?

like image 710
Francis Ducharme Avatar asked Jun 13 '16 14:06

Francis Ducharme


People also ask

What is an abstract class?

A class which contains one or more abstract methods is called an abstract class. An abstract method is a method that has a declaration but does not have an implementation.

Should I create my own WordPress plugin for abstraction?

Your Own Custom Abstract WordPress Plugin In the end, the best choice for abstraction will always be to create your plugin. It may seem like a big undertaking, but if you have limited ability to manage your WordPress core files directly, this offers an abstraction-friendly workaround.

What is the difference between interfaces and abstract classes?

Abstract classes are very similar to interfaces but they have different rules that a web developer need to be aware of. The definition is quite straightforward, basically, an abstract class is a class that contains abstract methods, Abstract methods are methods that have been declared but not implemented in the code.

What is the difference between concrete and abstract classes in Java?

Concrete classes contain only concrete (normal)methods whereas abstract classes may contain both concrete methods and abstract methods. The concrete class provides an implementation of abstract methods, the abstract base class can also provide an implementation by invoking the methods via super ().


2 Answers

Just because it is a base class doesn't eliminate the issue with class level variables in CRM plugins (and workflows.)

From https://msdn.microsoft.com/en-us/library/gg328263.aspx#bkmk_writingbasic:

For improved performance, Microsoft Dynamics CRM caches plug-in instances. The plug-in's Execute method should be written to be stateless because the constructor is not called for every invocation of the plug-in. Also, multiple system threads could execute the plug-in at the same time. All per invocation state information is stored in the context, so you should not use global variables or attempt to store any data in member variables for use during the next plug-in invocation unless that data was obtained from the configuration parameter provided to the constructor. Changes to a plug-ins registration will cause the plug-in to be re-initialized.

Having class level variables violates this stateless requirement.

My recommendation is to rewrite the plugin (and then do the same for the workflow) to have an object that holds the references for each call to Execute, thus allowing the code to meet the stateless requirement.

public class CrmObjects
{
    public IServiceProvider ServiceProvider { get; set; }
    public ITracingService TracingService { get; set; }
    public IPluginExecutionContext PluginContext { get; set; }
    public IOrganizationService Service { get; set; }
}

public abstract class BasePlugin : IPlugin
{

    public void Execute(IServiceProvider serviceProvider)
    {

        var crmObjects = new CrmObjects();

        crmObjects.ServiceProvider = serviceProvider;
        crmObjects.TracingService =
            (ITracingService)serviceProvider.GetService(typeof(ITracingService));

        crmObjects.PluginContext = (IPluginExecutionContext)
            serviceProvider.GetService(typeof(IPluginExecutionContext));

        IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        crmObjects.Service = serviceFactory.CreateOrganizationService(crmObjects.PluginContext.UserId);

        ExecutePluginLogic(crmObjects);
    }

    public virtual void ExecutePluginLogic(CrmObjects crmObjects)
    {
        throw new NotImplementedException();
    }
}

I wrote a blog article about doing something similar, http://nicknow.net/dynamics-crm-2011-abstracting-plugin-setup/, a few years back. In the model I described it didn't rely on a base class but used a class that was instantiated on the first line of the Execute method to accomplish the same concept. I've since moved to a base class model - similar to this design. When I get a chance I'll put it out on GitHub.

like image 197
Nicknow Avatar answered Oct 12 '22 22:10

Nicknow


Also, even if you ever make your base class generic (maybe based on the type of context that it retrieves), you'll need to add the : IPlugin interface to all plugins, even though the base class defines it.

like image 21
Daryl Avatar answered Oct 13 '22 00:10

Daryl