Today I am writing another post on the very hot topic which is “Events in dynamics NAV”.
This article contains a complete overview about how to play with the events in Microsoft Dynamics NAV.
This article contains a complete overview about how to play with the events in Microsoft Dynamics NAV. Today, we will discuss the following topics which are as under:
- Introduction to events.
- Why Events?
- Type of events
- Page Trigger events
- Database trigger events
- Global events
- Order of execution
- Publishing events
- Event type
- Include Sender
- Global Variable access with events
- Triggering an event
- Table trigger parameters.
- Best Practices
- Subscribing to an event
- Event Publisher Object
- Event Function
- Event Publisher Element
- Event Subscriber Instance
- Accessing Sender
- Accessing Global Vars
- Best Practices
- Overview of event subscriber
In layman’s term, if we try to define event it can be defined as: “the occurrence of something”. If we try to define events from developer point of view, the event allows us to develop new functionality without modifying actual source code.
Generally, the model of Event based programming is very old. Many programming languages implement this model quite time ago. Microsoft introduced the model of events in Microsoft Dynamics NAV 2016. It is not wrong to say that it’s a new version of the Hooks Pattern. As we know, in Microsoft Dynamics NAV, we have the advantage that Microsoft provides us the source code of all the standard objects and we can modify these objects to implement our customizations. But on the contrary, this makes our Upgrade process very difficult because Microsoft change its code in the newer versions and we have to merge our customized code with the Microsoft’s new code. What events do is, they allow us to separate our customize code from the Application core business logic. We can implement new functionality without modifying the standard application objects which leads us to easy upgrade.
Type of Events
There are different types of events in Microsoft Dynamics NAV which are as under:
- Business Events
- Integration Events
- Page Trigger events
- Database Trigger events
- Global Events
Business Events and Integration events are the only two type of events which we can create. We will discuss it one by one.
According to Microsoft the Business event type is meant to be defined once and basically never changed. There are actually no checks in place, but when you publish an event of type Business, you make a commitment that it’ll never change.
As far as I could see in the current NAV Version, even Microsoft hasn’t committed any event to never change.
Choosing the type business or integration will actually not have any influence on the way the event is handled.
The Integration event type is the second of the 2 possible types of a custom event. Its purpose is to let other code “integrate” with our code.
Usually whenever we create an event we normally create an event of type ‘Integration’.
Page Trigger Events:
A few actions on a page will automatically create page trigger events. This is an overview:
- OnBeforeValidateEvent (this is called when a field loses focus and it’s value was changed)
- OnAfterValidateEvent (same as above, but after page validate trigger)
Database Trigger Events:
Creating a table will automatically create available events. These events are as under:
- OnBeforeValidateEvent (for every field. When subscribing, you first select validate event, another option to select the field will become available)
- OnAfterValidateEvent (same as above, but after validation trigger of the field)
Global events are predefined events that are raised typically in Codeunit 1. Examples for this are OnAfterCompanyOpen and GetSystemIndicator.
Order of Execution:
When you change a record, it might be interesting to know in which order the code will execute. Let’s assume we are doing Record.INSERT; This is how it is execute:
- OnBeforeInsert (Table Trigger Event)
- Table Insert Trigger
- OnBeforeDatabaseInsert (Global event)
- DatabaseInsert trigger in codeunit 1 will execute
- OnAfterDatabaseInsert (Global Event)
- The record insertion itself will happen on the database
- OnAfterInsert (Table Trigger Event)
Let’s say we have 1 event published and multiple subscribers. There is currently no way to determine which event subscriber will be executed first. I heard someone say that they are currently executed based on naming. There is probably not a way to make sure it is, or to be sure it stays like this. Don’t try funky stuff to ensure your position.
Just know that if you have subscribed to an event, and your subscription is ok (meaning all parameters are correct, binding is ok), your subscriber will be executed.
When we create a new event ourselves we have a few properties:
Business or Integration event type. See the description above. Let’s say that we will mostly make events of type Integration.
When we subscribe to our publisher, the Sender object will automatically be added to our signature ByVar. This allows to get access to the public functions of the object while we have the exact instance of the object.
Global Variable Access (GlobalVarAccess):
This option is only available to event type Integration. It will allow the subscribers access to globally defined variables in the object. I will explain in “Subscribing to an Event” how to access them.
Triggering an event:
LOCAL [IntegrationEvent] PROCEDURE OnBeforeDoSomethingEvent()
LOCAL [IntegrationEvent] PROCEDURE OnAfterDoSomethingEvent()
LOCAL PROCEDURE DoSomething()
OnBeforeDoSomethingEvent; //Triggering on before event
OnAfterDoSomethingEvent; //Triggering on after event
Table Trigger Parameters:
In every table trigger, you might notice there is a RunTrigger boolean. It basically states if the default trigger will be executed.
In my opinion, it’s good practice to have custom events as local. They shouldn’t really be called from anywhere else than the object itself. It also makes finding the trigger point a lot easier when going through your code.
An event should not contain any code or locals.
Another good best practice is to never call a publisher from more than one place. You want subscribers to know what the event is. If there is need to subscribe to a publisher that is executing from multiple places, these should be done through the predefined trigger events.
Subscribing to an event:
Subscribing to an event is only possible in a codeunit.
Event Publisher Object:
Here we can select an object where we know an event is published.
We can select the available events. These can be trigger events or custom events.
Event Publisher Element:
When we select EventFunction of type validate or page action, we get an extra property. In this list we get an overview of possible element names.
- In the page action, we get an overview of all defined actions.
- In the page validate, we get an overview of all fields on the page.
- In the table validate, we get a list of all fields in the table.
Event Subscriber Instance:
This property is a property on codeunit level. It can be:
Static-Automatic: NAV will automatically enable the subscriber and link it to the publisher you defined.
Manual: The subscriber will not be executed until you enable it through code with the BINDSUBSCRIPTION and disable it with the UNBINDSUBSCRIPTION
In most cases the Static-Automatic, which is the default, is the way to go.
When the publisher has the IncludeSender enabled, it will include the sender in the parameters of the subscriber.
Accessing Global Variables:
Let me first start with saying that it is best to avoid accessing global variables. If they ever change, you might not notice when compiling, but your event subscriber will probably no longer work…
Anyway, how to do it. Actually pretty simple. First make sure the publisher has the property enabled, or it won’t work. Next in the subscriber, you add an extra parameter with the EXACT SAME name and data type. You need to do this manually for each global variable you wish to access. By setting it ByVar, you can also change them. Setting it ByVar is however not mandatory.
Again, you need to note that if the publisher object removes a global var you access, or changes it’s name, you will not get a compile error, but your subscriber will not get executed.
The subscriber functions should also be declared local. It is never a function that needs to be called manually.
If we go through coding, we just see the publisher functions, but we do not have the option to use “Go to definition” to see subscribers. In the “Event Subscriptions” overview, we can see everything that is subscribed, so this is the way to go.
When actually debugging the code, the debugger just steps into the subscription, while maintaining the call stack.
Overview of the event Subscriber:
NAV contains a virtual table with all event subscriptions. This can be accessed from the development client by going to Tools => Debugger => Event Subscriptions.
Another method of opening this page is by opening the Sessions page (also known as the “debugger”) from the windows client and clicking the “Event Subscriptions” button.
In this page we see the subscriber information (Codeunit, Function) and the publisher information (Object ID, Function, Type). The type of subscriber instance is also visible. But you have to note that if the instance is set to manual, the event subscription will only appear in the table as soon as it has been bound once. Another field shows how many times the subscriber has been fired.
Events are a really great tool to interact with the default coding of NAV without having to change the default coding. The more default integration events become available, the more we can use them. This will result in easier upgrading. Let’s say we subscribe to Codeunit 80 events to do extra stuff, we don’t need to worry if codeunit 80 gets changed completely. One big issue, which we do need to keep in mind, is “loosely binding” of events. We have the Event Subscriptions table where we can see if they are active, but we do not get compile errors, nor do the users get an error if the function is no longer bound. This could result in a lot of problems in a production database when some code is no longer run.
I hope you will like my article. I will cover the Demo in the next part, so keep watching my blog. 🙂