How it works...

In step 1 to step 16, we extracted all the methods related to the DAL into their own hierarchy. We started in step 1 to step 9 by creating a base concrete class along with its interface to give us basic reusable DAL methods, such as UpdateEntity (a polymorphic method that accepts any entity) and Commit. The base class's constructor instantiates the organization service context as it uses the unit of the work design pattern (as described in the Creating a LINQ data access layer recipe of Chapter 4, Server-Side Extensions). In step 10 to step 16, we created our e-mail-specific concrete DAL along with its interface. The concrete class inherits from the base class, thus including the accessible base class's methods.

From step 17 to step 22, we created a concrete tracing class along with its interface. This specific class simply wraps the CRM tracing service functionality.

S stands for Single responsibility in the SOLID principle. Having separate DAL classes ensures that each class has a single responsibility.

In step 23 to step 27, we extracted the business logic to call the load and update e-mail methods into a separate business logic class. This class is only dependent on the previous two interfaces created (IEmailDataAccessLayer and ICustomTracingService) and is unaware that the concrete classes are connected to Dynamics 365.

D stands for Dependency inversion in the SOLID principle. Our business logic is dependent on interfaces (abstraction), not concrete classes.

In step 28 to step 31, we created a factory class to generate the two concrete classes we created previously, but each method's return type is an interface. The factory uses the singleton pattern to ensure we can reuse classes that are already instantiated. Furthermore, the factory implements IDisposable to dispose the DAL classes properly.

In step 32 to step 41, we refactored what is left from the original plugin into an abstract base class and a child class. The base (BasePlugin) deals with the most common generic elements of a plugin; it handles extracting the organization service, instantiating the factory class and the tracing service, and handling exceptions by wrapping the plugin execution in a try catch statement.

In step 38 to step 42, we implemented our specific plugin that now inherits from the base plugin. Given that most of the plugin handling details are in the base class, and that the specific work done by the plugin was extracted to the business logic, all we need to do in our concrete class is instantiate the business logic, inject the correct dependencies, and call the correct method on the business logic. Two lines of code in the overridden PostExecute method plus one line to override the ExpectedEntityLogicalName getter to return the entity's logical name is all that are needed.

Note how we created the majority of the classes as public. This ensures that we can access them from external assemblies to extend them. Feel free to restrict the accessibility as you see fit however; do not expose your classes for the sake of unit testing. Without going too much into a philosophical unit testing debate, Visual Studio allows you to unit test restricted methods if necessary.

O stands for Open/Close in the SOLID principle: open for extension, but close for alteration.

Our one class plugin has now turned into 10+ classes. The new class diagram now looks like this:

Note how the business logic is only dependent on interfaces (dependency arrows between BusinessLogic and ICustomTracingService or IEmailDataAccessLayer). This is a good example of fundamental object-oriented paradigms at work (encapsulation and polymorphism when injecting mocks or stubs).

L stands for Liskov substitution in the SOLID principle. As we will see in the next recipe, we will replace the concrete DAL with a different implementation without altering the correctness of our code.

The abstract base plugin is now only dependent on the factory class and the tracing interface. The concrete plugin is only dependent on the business logic (and also the factory and the tracing interface through its inheritance). The factory is the only class dependent on concrete classes. You can further enhance the factory class to use reflection to load the correct class (configuration-driven instantiation), also rendering it indirectly dependent on the concrete classes.

Why did we complicate our simple one class code? We did that for the sake of better design; the new design follows the SOLID principal. The classes are small and loosely coupled yet cohesive. There is no direct dependency to concrete classes, which means unit testing our business logic is much easier. Given that the actual plugin has been simplified and that it delegates most of the work to the business logic, which enables us to convert our plugin to something else. For example, we can change it to a unit test to test our business logic without using the Dynamics 365 user interface by simply injecting a live Dynamics 365 DAL. Alternatively, we can easily convert a plugin into a custom workflow activity (as described in the Converting your plugin into a custom workflow activity recipe later in this chapter).

Be pragmatic when refactoring your code. If your project has only a couple of small plugins, this may be an overkill. However, if your instance is heavily customized, then this design ensures consistency in your code, clean unit testable classes, and significant minimization of code duplication through reusability.

Keep in mind that layering introduces abstraction; if you are writing a pre-update plugin that requires a close interaction with pre-images, make sure you deal with the object appropriately between your layers; otherwise, you might lose context details through the abstraction.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset