Discovery Event Pattern

I have been working on describing this very interesting NAV Design Pattern that uses events. We have been implementing it a few times, and I just didn’t want to hold it from you. You can find the pattern on “The Microsoft Dynamics NAV Design Patterns Wiki“. The actual design pattern can be found here, but just for googling reasons, I’m repeating it below :-).



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”.


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.


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.

5.00 avg. rating (99% score) - 6 votes

Permanent link to this article:


6 pings

Skip to comment form

    • Thomas Sigurdsson on March 2, 2016 at 6:00 am
    • Reply

    Dear Waldo,

    In the SetupModule function you are using Hungarian Notation on your parameters?


      • waldo on March 2, 2016 at 6:11 am

      Yes, only in that situation: when I use a WITH, which would cause a mixup between paramaternames an fieldnames. I need my parameter to be different from the field.

      • Thomas Sigurdsson on March 2, 2016 at 7:34 am

      I can certainly see the problem, I would instead of using Hungarian Notation use either a shorten name for the variable or in this case use a more describing name like: ModuleCode, ModuleDescription, ModuleEnabled
      Then your would avoid using the troublesome H.N. and when referering to the function from another object you would not see the H.N. but a more precise variable name.

      Just my thoughts on this 😉

      • waldo on March 2, 2016 at 8:06 am

      And thank you for your thoughts :-). So let me give mine …

      And it makes sense in both ways, I guess. Personally, the “p” doesn’t bother me. It actually tells me: “hey, be careful, there are multiple instances of this kind of variable to be used in this function” :-).
      Your proposal makes much sense .. but then again .. “Module” is just a prefix, while the “p” is as well. ;-). But I might just as well done it that way. As a matter of fact .. when I’m thinking of it now .. when this scenario happens with normal variables, I’m doing it your way :-).

      In any case .. I guess it’s personal. This occasion is the ONLY place I use this “HN” .. and I can live with it ;-).

    • Thomas Sigurdsson on March 2, 2016 at 7:48 am
    • Reply

    Another thought on this…

    We are implementing a large new NAV 2016 company specific solution. And we are heavily using both subscribers and publisher – all just fine.

    We have been talking a lot about how to structure these and have for now decided to create some additional codeunits to be able to get an overview.
    We have made the following codeunits:
    – “Table Subscriptions”
    – “Codeunit Subscriptions”
    – And several codeunits to have the actual business logic.

    So our Subscription Codeunits will only have a single line of code calling the business logic codeunit.

    This should give os a better overview of what subscriptions we have.

    What are your thought on this approach?

      • waldo on March 2, 2016 at 8:39 am

      Well, this would lead me to a very large answer. What I can do, is refer to our “PowerShots”, where there is a session on it where we handle this in depth.

      But let me try to be very short…
      First, I implement the hook pattern quite a lot. These might be your “table subscriptions”, but I have a codeunit per table. The subscriptions usually call out to methods by using its class (tables – see below): which is our second type of codeunit .. and most important: One method is one codeunit. All functions related to the method are in this codeunit. Decoupling is done by using eventing and implement the “VAR Handled pattern” on these methods.. .
      As such, we treat a table as a class .. and call out to methods by calling them through the table (OO approach) .. which is what we do in these hook, actions on pages, other methods, .. .

      It’s just too much to note down, and each part can easily take a few pages of description.. . We ARE going to describe it by the way, and it’s going to be part of the learning portal. Can’t tell you dates, however.. .

  1. Personally I am not in favor of decoupling everything by default as is evangelised by Gary. I think this should only be done if there is a functional requirement.

    Also, if you implement decoupling, make sure you have a strong contract that prevents abuse of the subscription. This can be done using the Arugment pattern.

      • waldo on March 2, 2016 at 10:32 am

      It is not only evangelized by Gary – I’m totally in favor and implementing it as well. :-). Just take a look at my methods of WaldoNAVPad ( 🙂

      How I look at it: decoupling is implemented to facilitate “unforeseen” implementations and customizations in the future. Quite hard to have functional requirements for all the requests in the future. It’s an architecture/pattern to facilitate enhancement in the future… . Again, that’s how I look at it personally – and why we implement it by default.

      Totally right on the contract. But working with the “sender” in events somewhat makes it more interesting than implement the facade pattern.. .

    • Thomas Sigurdsson on March 2, 2016 at 11:20 am
    • Reply

    I do think that Gary has laid out the path for us and to some degree we do absolutely following this path.
    But in most user cases we do not have access for endless amounts of codeunit to implement this completely.
    So we have “for now” chosen a middle way when talking about the hooks pattern, where we collect functions in codeunit based on the application area like Sales, Purchase, Inventory etc.

    I think the next big issue that must be discussed is now to structure the application, when using subscriptions.
    Would the “Gary” way be to implement a codeunit to house the subscribers per object (Table/codeunit/page) or to collect them?

      • waldo on March 2, 2016 at 12:43 pm

      Please do know we’re usually are talking about “Product Development”, which leads to some assumptions: a product should get certified, and when certified, the amount of objects is not that “important” anymore. As an example: I have 4000 codeunits in my license.

      Also, when working for customers, some other design principles apply. One example: decoupling makes somewhat less sense, in my opinion.

  2. The challenge is to stay pragmatic. People like “rules” and someone telling them when to do what. This is the biggest issue when evangalising good coding principles.

    In case of an interface, and especially when doing Waldo NAVPad you are correct. But 95% of code written by NAV developers is not required to be generic, and generics can be super dangerous when given to the wrong people. This is why Navision is not generic.

    I don’t think everything should be a codeunit of its own, even when you make a product. Very often your code can be a simple function on the table with a few local variables. Then if you make a codeunit you should decide if you really want people to be able to override what you intend to do.

    This is especially true in a cloud environment where you have 100% control of the code. In one of our last PRS meetings we talked about dirty code being more possible in those scenarios.

    Damn I miss those meetings.

      • waldo on March 2, 2016 at 1:41 pm

      Well, all kinds of architecture is food for thoughts. I have regular meetings with my developers to try to nail down an architecture .. or “rules” as you say .. that fits for us as product team, customer customizations, .. .

      Any kind of development is dangerous .. developers have great power – and with great power comes great responsibility 🙂 (Spiderman’s uncle was a wise man…)

      Generic design has helped us in many ways. I love it. I apply it as much as I can, in places where it makes sense.
      – It makes your app more stable, as you have expected behavior on all places you use the generic solution. If there is a bug, it’s a consequent bug, and needs to be solved only once.
      – you avoid code cloning – which is usually caused by not making the functionality generic enough. For example: when you use RecRefs, it’s already quite generic. But put Variants on top of it, and you avoid two lines of code cloning 🙂
      – less code is needed, so it contributes to upgrades
      – functionality behaves the same – people’s expectations are the same
      – …
      I LOVE generic design .. and in many cases, I apply that design to various functionalities in our product.

      About overriding code. I think it’s the other way around: People that want to override it, should know what they are doing. Closing down the app, just because we “think” people are not capable does not drive my design principles … ;-). I’d rather open it up, and assume people are capable, and give them all the opportunities I can give them.. . Sure, “assumptions is mother of all fuckups”. But then again, “assumptions is mother of all opportunities” in this case ;-).

      But that’s the beauty of these discussions. Different opinions, different architecture, different code design .. interesting :-). That’s why I think there are so many patterns .. because we need them to drive our personal opinions. 🙂

  1. […] Continue reading » […]

  2. […] Continued on Source: Discovery Event Pattern » waldo's blog […]

  3. […] needed. To enable this, I used the Discovery Event pattern as explained on Waldo’s blog: And again (like the SMS web service example), the setup table uses this pattern for secure storing […]

  4. […]  I like to look at this as an external service so I link the setup to the Service Connections, Waldo calls this the Discovery Event Pattern.  I create the following function in a Codeunit to register the […]

  5. […]  I like to look at this as an external service so I link the setup to the Service Connections, Waldo calls this the Discovery Event Pattern.  I create the following function in a Codeunit to register the […]

  6. […] notification is being added to My Notifications based on the discovery design pattern. This can easily be achieved with a subscriber to the OnInitializingNotificationWithDefaultState […]

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.