Discovery Event

by waldo

Abstract

The “Discovery Event” pattern is a way for a generic functionality, to call out to other functionalities that want to make use of it, by raising an event, so that they have an event to subscribe to. This is usually done to set itself up within the generic app.

The problem

Let’s suppose you have a generic piece of functionality, that hooks into lots of places (modules) in your application. To set this up, you might have to hook into all these parts of the application. Well, this pattern turns this setup around: let all the different modules set itself up in the generic app by raising a “discovery event”.

Usage

The pattern is most easily described when you look at an example. This example is an actual usage of the pattern within the application, in page Service Connections.

The goal of this functionality is to:

  • List all the different connections to external services,
  • Have a central place to navigate to the corresponding setup of the service.

The functionality (Service Connections) itself, is not aware of the state nor setup nor any context of all the different services in the list. All it does is:

  • It raises an event as an opportunity for all services within the NAV application to subscribe to,
  • It has a public function InsertServiceConnection that the subscribers can use to register itself at the Service Connection.

The event OnRegisterServiceConnection is raised when the page (1279 - Service Connections) is opened.

One example of a subscription is the SMTP setup. In Codeunit 400 you’ll find the subscriber function HandleSMTPRegisterServiceConnection which subscribes to this discovery event, and calls the InsertServiceConnection to register itself.

Description

The main idea of this pattern is: “Discover the settings, the context, the records, … which I need for my functionality” or “Discover the configuration for my functionality”. In any case, “discover” is the main idea. It’s a pattern where using both publishers and subscribers in one application makes a lot of sense.
Let’s break down to the steps that are needed to implement the pattern.

Step 1: Publish the event

In the below example, I create a table Module Status with a published event OnDiscoverModuleStatuses.

You see that I also include the sender. This way, I will be able to access the methods on my table (which I use as a class). Obviously, other patterns can be applied here as well, like the Argument Table pattern.

Step 2: Raise the event on the right place

When you publish an event, it should obviously be raised somewhere in the code as well. In the below example, I want to raise the event simply by a method which I want to call from a page. So I create a global function where I raise the event:

Step 3: Create one or more global functions, so that your subscriber can call into your functionality to configure, set up, or do whatever it needs to do to make itself discoverable

The generic functionality that I want to call, should be part of the main class - in this case the Module Discovery class, or better, the table (Module Status). In this table, I create this global function, because I want to make it available for the subscribers:


The business logic doesn’t really matter for this pattern. This is obviously dependent on the functionality where you would like to implement the pattern.

Step 4: subscribe from the places in the app to this event, use the global function(s)

This could be anywhere. Any module within your vertical, of within the main application, can subscribe to the event. In the example below, I create the subscriber in Codeunit80, as I was interested in the status of the Sales-module in default NAV.
The exact place of the subscriber is up to you. The main message is that it’s part of the module that wants to subscribe, and not part of the Module Status module in the application.
Here is the subscriber (and one small helper function):


You see I can use the “sender” as a normal Record-variable. I access the previously created global function to “register” this sales-module.

Microsoft Dynamics NAV Versions

This pattern only works with Microsoft Dynamics NAV 2016 and up.