Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 11: Extensions and Customizations

Objectives

By the end of this chapter you will be able to:

  • Explain what an AL extension is and why it’s preferred over modifying base code
  • Read and edit the main fields in app.json
  • Create a permission set that grants access to your own objects
  • Extend standard behavior with an event subscriber instead of changing base code
  • Apply extension-packaging best practices you can defend in a code review

11.1 What is an extension?

Customizing Business Central used to mean editing Microsoft’s own source code directly. That was risky, and it made upgrades painful. An extension is a separate package of AL objects (tables, pages, codeunits, and so on) that adds or changes behavior without touching the base application’s code.

Everything you’ve built so far already lives inside an extension: the Loan Repayment Schedule table, its page, and the Loan Repayment Mgt. codeunit. This chapter is about packaging that extension properly and extending other objects safely.

11.2 Anatomy of app.json

Every extension has an app.json manifest that describes what the extension is and what it depends on.

{
  "id": "b1f0c1a2-1234-4a1b-9c3d-1a2b3c4d5e6f",
  "name": "Loan Repayment Management",
  "publisher": "Your Company",
  "version": "1.0.0.0",
  "brief": "Track loan installments and repayment status.",
  "idRanges": [
    {
      "from": 50100,
      "to": 50149
    }
  ],
  "dependencies": [],
  "runtime": "12.0"
}

Hint: If an object ID falls outside the range declared in idRanges, the extension won’t compile. Reserve a range early and keep every object you create inside it.

11.3 Permission sets

Creating a table doesn’t automatically let anyone use it, because Business Central denies access by default. A permission set grants access to your objects as a named bundle that you can assign to users or roles.

permissionset 50100 "Loan Repayment"
{
    Assignable = true;
    Caption = 'Loan Repayment Management';

    Permissions =
        table "Loan Repayment Schedule" = X,
        tabledata "Loan Repayment Schedule" = RIMD,
        page "Loan Repayment Schedule List" = X,
        codeunit "Loan Repayment Mgt." = X;
}

Hint: Access to a table’s rows is granted on tabledata, with R, I, M, and D for read, insert, modify, and delete. X on a table, page, or codeunit only lets the user run or open that object; it doesn’t give access to any data. For a read-only reporting role, grant tabledata ... = R instead of RIMD. Don’t give everything full access just because it’s less to think about. That kind of blanket grant is exactly what a security review will flag.

11.4 Extending without modifying: event subscribers

Sometimes you want to react to something that happens in a standard object without touching that object. Microsoft publishes events for this, so you write a subscriber to the event instead of a modification.

codeunit 50101 "Loan Repayment Event Subscribers"
{
    [EventSubscriber(ObjectType::Table, Database::Vendor, 'OnAfterInsertEvent', '', false, false)]
    local procedure OnAfterInsertVendor(var Rec: Record Vendor)
    begin
        Message('New vendor %1 created — remember to check for outstanding loans.', Rec."No.");
    end;
}

Hint: The Message here is only for learning. In a real extension, a subscriber usually does something quieter, such as writing a log entry, creating a related record, or setting a default. A dialog popping up on every vendor insert would annoy every user in the company.

11.5 Best practices for extensions

  • Reserve your ID range once and stick to it. Mixing ranges across extensions is a common cause of deployment conflicts.
  • Grant the minimum permission needed: R on table data where read-only access is enough, and RIMD only where users must change data.
  • Prefer event subscribers to any form of base-object modification. Subscribers survive Microsoft’s updates, and modifications don’t.
  • Name each permission set so its purpose is obvious from the caption alone. “Loan Repayment Management” does that; “Custom Perms 1” doesn’t.

Chapter summary

In this chapter you:

  • Learned why extensions replaced direct changes to base code
  • Read the main fields of app.json and what they mean
  • Created a permission set that grants access to your own objects
  • Wrote an event subscriber that reacts to a standard table without modifying it

Tasks

  1. Write your app.json. Create one for the Loan Repayment extension with an idRanges block covering 50100–50149, and confirm every object you built in Chapters 7–9 falls inside it.
  2. Create the permission set. Add permissionset 50100 "Loan Repayment" granting RIMD on your table’s data and X on your table, page, and codeunit.
  3. Add an event subscriber. Subscribe to Vendor’s OnAfterInsertEvent (or another standard table’s insert event) and log or message something relevant to your extension.
  4. Try it yourself. Your permission set currently grants full RIMD access to the loan data. If you wanted a “read-only auditor” role that could view loan data but never change it, what would you change?

Check your work: compare your files against the reference solution in the Chapter 11 solutions.