A Short Overview of the Article
This article explores the benefits of developing a base class for plugins, focusing on how it can enhance code description, readability, and maintenance in Microsoft Dynamics 365 CRM.
The presented approach uses inheritance, custom attributes, and Reflection to separate plugin registration information and technical execution logic from the business logic. The goal is to create a reusable plugin container that reduces repetitive code while providing a clear and consistent development pattern.
The following sections first examine the conventional approach to implementing a Dynamics 365 CRM plugin and the challenges that arise when this approach is applied to a growing system. The article then introduces the proposed base class architecture. It explains how to identify plugin methods, read their registration parameters, and select and execute the appropriate method based on the current CRM context.
A Short Reference About the Author
Mykhailo is an experienced and highly skilled Dynamics 365 Developer with extensive hands-on experience across Dynamics 365, Power Platform, Azure, AI, and a broad range of Microsoft technologies.
Introduction
Clear and maintainable code is essential in complex systems such as Microsoft Dynamics 365 CRM. Plugins extend CRM functionality through custom C# code for tasks such as business rules, data validation, record updates, and integrations.
However, plugins often repeat technical code for handling execution contexts, services, tracing, and parameters. This repetition can reduce readability, increase maintenance effort, and cause inconsistencies.
A common base class can encapsulate this technical infrastructure, providing consistent service initialization, context validation, and execution structure. This allows individual plugins to focus mainly on their business logic, improving code quality and maintainability.
Basic Approach
Creating a basic plugin for Microsoft Dynamics 365 CRM involves writing a class in C# that implements the IPlugin interface. Here's an example of a simple basic plugin:

Once in this form, the plugin can be registered and will work. However, typically, the developer also checks the correctness of the input parameters (whether the plugin is registered correctly):

Additionally, the services for CRM interaction require initialization:

When scaling a system, a necessity arises to create new plugins and modify existing ones. One of the crucial aspects of this process is maintaining clean code. The following problems can arise with such an approach:
-
Repetition of technical code
-
Context checks that can be missed (which can be critical if the plugin is not registered correctly)
-
Technical code distracts attention from the main business logic
All the drawbacks mentioned above can be addressed by creating a base class for plugins, which will handle service initialization and necessary checks and eliminate the code repetition.
Base Class for Plugins
Once again, briefly, about the basic approach - we implement the IPlugin interface, add our code to the Execute method, and obtain a plugin class, which we register using the Plugin Registration Tool. In the case of the base class, the approach will look slightly different: we inherit the CrmPluginContainer class, add methods with specific signatures, mark them as plugins, and as a result, we get a class with one or several plugins that are registered similarly to the basic approach. What is required for this?
First, we must implement a mechanism that recognizes which class method is a plugin and reads its registration parameters. An excellent solution for solving this task would be attributes:

The next essential mechanism involves searching for methods marked with such attributes and reading registration data:

The process is straightforward: through Reflection, the registration parameters specified in the attribute are condensed, forming a representation of the plugin, which is then appended to the overall array. The subsequent step involves crafting a class that consolidates all the plugin's input parameters and pre-initialized services for seamless communication with D365 CRM:

With a list of plugin concepts and the context of the base plugin (a class containing methods marked with an attribute), you can decide which methods need to be called:

Now, it remains to unite this into one mechanism:

The typical workflow is as follows:
-
Create a class inheriting from the "CrmActionContainer".
-
Add methods with the signature void "MethodName(CrmPluginContext context)" to the class.
-
Mark these methods with the attribute [CrmPlugin("Create," "Account," StageCodePost)].
-
Implement necessary business logic within these methods.
-
Register the container class.
-
When the trigger is activated, the "Execute" method is called, initiating the mechanism of the base class created.
-
Initially, all plugins marked with the attribute are located.
-
Their registration data is then examined to determine which plugins need to be executed based on the current context.
The example of usage:

Conclusion
This article extensively discussed the principles and advantages of using a base class for plugin development in Microsoft Dynamics 365 CRM. The key point is that implementing such an approach simplifies and optimizes the development process, making the code cleaner, more understandable, and easier to maintain.
The given method allows developers to focus on the specific logic of the plugin, minimizing the repetitive code, and reducing the likelihood of errors. It also promotes other developers' better understanding of the code, essential in teamwork. The base class is an excellent foundation for creating structured and efficient plugins.
Frequently Asked Questions
A base class centralizes common technical tasks such as service initialization, execution-context validation, and plugin discovery. This reduces repetitive code, improves consistency, and allows developers to focus more directly on implementing business logic.
Each plugin method is marked with a custom attribute containing registration information, such as the message, entity, and execution stage. The base class uses Reflection to discover these methods and compare their registration parameters with the current CRM execution context. Only the methods that match the current event are executed.
The registration process remains conceptually similar to a standard plugin. The container class is registered with the Plugin Registration Tool, while the custom attributes define which methods should respond to particular CRM events. This allows multiple plugin methods to be organized within a common container while retaining the standard CRM registration model.
A base class is particularly useful in projects with multiple plugins, shared development teams, or complex CRM customizations. As the number of plugins grows, centralizing common execution logic can significantly improve code consistency, readability, and maintainability while reducing the chance of missing important context or service initialization steps.
Related Content
UDS Blog articles:
