Delegates and Event Handlers in D365FO

How often did you find yourself in a situation when you created a Dynamics 365 Finance and Operations customization and wanted to create a logic which can respond to changes or notifies your change to future extensions of your code?

By using delegates and event handlers, you can define and handle custom events that are triggered by actions or changes in your application, such as user interactions or changes to data. This allows your code to be more modular, reusable, and easier to maintain, as different parts of the application can interact with each other without having to know the implementation details of the other parts.

What are delegates and event handlers?

A delegate is a type of object that references a method. In other words, a delegate refers to a function that can be passed as an argument to another method, making it easy to write code that can be executed dynamically at runtime.

On the other hand, an event handler is a method that is executed in response to a specific event occurring in the application. For example, in D365FO, you can create an event handler for a button click event, and your code will be executed when the user clicks the button. Event handlers are useful because they allow you to create custom logic that can be executed when specific events occur in your application, making it possible to add custom functionality in the future.

Why would I use delegates and event handlers?

There are several reasons why you would use delegates and event handlers in D365FO applications:

  1. Dynamic behavior: Delegates allow you to pass a method as a parameter to another method, enabling you to write code that can be executed dynamically at runtime. This is useful when you want to allow users to define the behavior of the system in a flexible way or when you want to make it easy to add or modify the behavior of the system without having to change the code directly.
  2. Customization: Event handlers allow you to create custom logic that can be executed when specific events occur in your application. This enables you to add custom functionality to the system, such as capturing data from the user or triggering a specific action in response to an event.
  3. Reusability: Delegates and event handlers can be used in multiple places within your application, making it easier to reuse code and reducing the amount of time and effort required to maintain the codebase.
  4. Decoupling: Delegates and event handlers allow you to decouple different parts of your application, making it easier to change the behavior of one part of the system without affecting other parts. This can make it easier to maintain and modify your application over time.
In D365FO, when we invoke a delegate, it raises an event allowing all method subscribers (i.e. event handlers) to execute and handle it. Thus, for each delegate in D365FO, we can create event handler methods, which are methods decorated with the SubscribesTo attribute pointing to the delegate and a signature identical to the delegate signature (both parameters and return type).

Delegates in X++ must have the return type void, so we need to use objects (e.g. EventHandlerResult) as method parameters to return a result.

Usually, we customize D365FO built-in functionalities by subscribing to (the events raised by) the delegates created by Microsoft and invoked in the standard code.

What about the traps using delegates and event handlers?

Delegates and event handlers in X++ can be used in various scenarios such as:

  1. To notify the subscriber on a change that has happened in your implementation.
  2. To request a change in a behavior of the code flow based on the event handlers result.

The first scenario is quite straight forward as we call the delegate with a fire and forget principle, and all the subscribers will get notified about the change.
However, in the second scenario we can quickly introduce a few traps. Let’s us now look the problem through an example.

We are creating a customization where we want to upload a file. We want others to extend our implementation by adding their own logic for file security checks before we store the uploaded file to D365FO, such as:

  1. Check the file with a virus scanner of your choice.
  2. Check if the file is on a whitelist file extension.
  3. Check if the file is on a blacklist file extension.
  4. Any other possible check you can imagine 😊.

Our code above shows how simple it is to use delegates and event handlers and the code is totally legit.

So, what is the problem with our implementation:

  • We have more than one subscriber doing different file security checks and each of them can return a different result.
  • Each of the subscriber will return a file security check result and the last one called will win, and the result from the previous subscribers will be overwritten.
  • We used a principle of method return value, which is a bad coding pattern when writing event handlers as we are not in control of the resulted value.

Now that we are aware of the traps, let us look at a possible scenario that can solve the above problem.

The Solution: Ensuring only one response

A better approach is to create an object and pass it as a parameter to the delegate. This way you can implement a class which can prevent setting multiple responses.

Lucky for us 😊, D365FO already has a mechanism in place to prevent the unexpected behavior with the so-called EventHandlerResult class. The class has an additional static constructor called newSingleResponse(), which ensures that the logic fails if more than one subscriber provides a result with the message ‘Only a single subscriber is allowed to respond with a result’.

Out of the box D365FO comes with two simple implementations to accept (EventHandlerAcceptResult) or reject (EventHandlerRejectResult) the event result.You can read more about D365FO EventHanderResult and it’s implementations here in the Microsoft documentation.

In the following example we will be using a simple implementation of EventHandlerResult class called EventHandlerRejectResult.

Similar logic can be applied to affect the code flow in D365FO in different areas. You can search for all references where the classes EventActionHandler, EventHandlerAcceptResult or EventHandlerRejectResult are used.

We are listing just a few delegates to which you can subscribe and create a custom logic including the Docentric one 😉:

  • Docu::delegateScanDocument(),
  • Docu::delegateScanDeletedDocument(),
  • FileUploadResultBase::delegateScanStream(),
  • DocReportTemplate::onUploadingTemplate(),
  • and others.

Final Thoughts

Delegates and event handlers can make your life as a developer easier to produce more modular, reusable, easier to maintain code and allow you to interact with others without having to know the implementation parts.

However, be aware of all the pitfalls described in this article especially if you are expecting from the subscriber a result which will change the behavior of your code.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Docentric respects your privacy. Learn how your comment data is processed >>

Docentric respects your privacy. Learn how your comment data is processed >>