Address remaining Marketplace review feedback

This commit is contained in:
demiliani 2026-09-11 16:39:28 +02:00
parent a300675320
commit 0e5351ed5d
11 changed files with 16 additions and 76 deletions

View file

@ -17,10 +17,10 @@ Profiles delivered by a Marketplace extension must be declared as AL `profile` o
Declare each app-owned profile with the `profile` object and set its `RoleCenter`, user-facing caption, and optional customizations in AL. Let installation and synchronization register the object.
See sample: `define-profiles-as-al-objects.good.al`.
See sample: [`define-profiles-as-al-objects.good.al`](define-profiles-as-al-objects.good.al).
## Anti Pattern
Install, upgrade, or setup code that creates an app-owned profile by inserting a `Profile` table record. Detection signal: a `Record Profile` variable followed by `Insert` in profile provisioning code.
See sample: `define-profiles-as-al-objects.bad.al`.
See sample: [`define-profiles-as-al-objects.bad.al`](define-profiles-as-al-objects.bad.al).

View file

@ -17,10 +17,10 @@ Marketplace extensions run for users and services in many time zones. Adding a f
Store and compare `DateTime` values without a manually applied regional offset. Business Central stores `DateTime` values in UTC and presents them according to the client time zone. Keep service contracts time-zone explicit and perform a conversion only when the business requirement identifies a particular zone.
See sample: `do-not-hard-code-time-zone-offsets.good.al`.
See sample: [`do-not-hard-code-time-zone-offsets.good.al`](do-not-hard-code-time-zone-offsets.good.al).
## Anti Pattern
Adding or subtracting a fixed duration solely to convert `CurrentDateTime` or another timestamp to an assumed local time. Detection signals include fixed hour-sized millisecond values near `DateTime` assignments and comments naming a specific time zone; confirm the duration is an offset rather than a legitimate deadline or schedule interval.
See sample: `do-not-hard-code-time-zone-offsets.bad.al`.
See sample: [`do-not-hard-code-time-zone-offsets.bad.al`](do-not-hard-code-time-zone-offsets.bad.al).

View file

@ -1,13 +0,0 @@
codeunit 50100 "Rental Company Open"
{
[EventSubscriber(ObjectType::Codeunit, Codeunit::"Application Management", OnAfterCompanyOpen, '', false, false)]
local procedure InitializeRentalSetup()
var
RentalSetup: Record "Rental Setup";
begin
if not RentalSetup.Get() then begin
RentalSetup.Init();
RentalSetup.Insert(true);
end;
end;
}

View file

@ -1,13 +0,0 @@
codeunit 50100 "Rental Feature Setup"
{
procedure EnsureInitialized()
var
RentalSetup: Record "Rental Setup";
begin
if RentalSetup.Get() then
exit;
RentalSetup.Init();
RentalSetup.Insert(true);
end;
}

View file

@ -1,30 +0,0 @@
---
bc-version: [all]
domain: appsource
keywords: [onbeforecompanyopen, onaftercompanyopen, company-open, event-subscriber, login]
technologies: [al]
countries: [w1]
application-area: [all]
---
# Do not subscribe to company-open events
## Description
Marketplace extensions must not subscribe to `OnBeforeCompanyOpen` or `OnAfterCompanyOpen`. These events run on the sign-in path, where an error can prevent access and even small amounts of work affect every company open. Move initialization to installation, upgrade, new-company initialization, or the first use of the feature instead.
## Best Practice
Initialize app data from install or upgrade code when its lifecycle belongs there. For work that can wait, perform an idempotent check when the feature is first used or schedule background work. Use `OnCompanyInitialize` only for data that must be created for a new company.
See sample: `do-not-subscribe-to-company-open-events.good.al`.
## Anti Pattern
An event subscriber bound to `OnBeforeCompanyOpen` or `OnAfterCompanyOpen`, even when its current body appears lightweight. Detection signal: either company-open event name in an `EventSubscriber` attribute.
See sample: `do-not-subscribe-to-company-open-events.bad.al`.
## See also
`community/knowledge/performance/oncompanyopen-subscribers-must-not-do-io.md` covers I/O and other expensive work on adjacent session-open events.

View file

@ -17,10 +17,10 @@ Pages and codeunits exposed as web services run without an interactive client. C
Keep service entry points and every procedure they call free of interactive UI. Return data through the service contract and report validation failures with service-safe error handling. When a procedure is shared with an interactive client, guard UI-only behavior with `GuiAllowed` while preserving the underlying operation.
See sample: `keep-web-service-paths-free-of-ui-calls.good.al`.
See sample: [`keep-web-service-paths-free-of-ui-calls.good.al`](keep-web-service-paths-free-of-ui-calls.good.al).
## Anti Pattern
A web-service-exposed page or codeunit calls an interactive UI method directly or indirectly. Detection signals include `Message`, `Confirm`, `StrMenu`, `Page.RunModal`, and confirmation-dialog pages on a service call path. Treat `Message` as suppressed and ineffective, not as a callback failure. Do not flag a controlled `Error` solely because it returns a service fault.
See sample: `keep-web-service-paths-free-of-ui-calls.bad.al`.
See sample: [`keep-web-service-paths-free-of-ui-calls.bad.al`](keep-web-service-paths-free-of-ui-calls.bad.al).

View file

@ -17,10 +17,10 @@ Place new page-extension actions at the beginning or end of an existing action g
Choose the semantic action area or group and append or prepend the extension's actions. This keeps placement deterministic without depending on the continued existence of one neighboring action.
See sample: `place-page-extension-actions-with-addfirst-or-addlast.good.al`.
See sample: [`place-page-extension-actions-with-addfirst-or-addlast.good.al`](place-page-extension-actions-with-addfirst-or-addlast.good.al).
## Anti Pattern
Using `addbefore` or `addafter` to place newly added actions next to a specific action from another app. The syntax is valid AL, but the placement anchor is brittle for a Marketplace extension.
See sample: `place-page-extension-actions-with-addfirst-or-addlast.bad.al`.
See sample: [`place-page-extension-actions-with-addfirst-or-addlast.bad.al`](place-page-extension-actions-with-addfirst-or-addlast.bad.al).

View file

@ -17,10 +17,10 @@ Pages and reports that users are expected to open directly must set `UsageCatego
Set `UsageCategory` to the category that matches the entry point, such as `Lists`, `Tasks`, `ReportsAndAnalysis`, or `Documents`. Also set the appropriate object-level `ApplicationArea` so search results respect feature visibility.
See sample: `set-usagecategory-on-searchable-entry-points.good.al`.
See sample: [`set-usagecategory-on-searchable-entry-points.good.al`](set-usagecategory-on-searchable-entry-points.good.al).
## Anti Pattern
A user-facing page or report intended for direct discovery omits `UsageCategory` or sets it to `None`. Do not infer intent from the object type alone; require evidence that the object is a direct user entry point.
See sample: `set-usagecategory-on-searchable-entry-points.bad.al`.
See sample: [`set-usagecategory-on-searchable-entry-points.bad.al`](set-usagecategory-on-searchable-entry-points.bad.al).

View file

@ -4,7 +4,7 @@ codeunit 50100 "Rental Period Defaults"
var
PolicyStartDate: Date;
begin
Evaluate(PolicyStartDate, '01/02/2025');
Evaluate(PolicyStartDate, '01/31/2025');
exit(PolicyStartDate);
end;
}

View file

@ -17,10 +17,10 @@ Write fixed dates in AL with the invariant `yyyymmddD` syntax. A locale-dependen
Represent a fixed date directly as an AL date literal, such as `20250131D`. Use `CalcDate` with a date formula when the value is relative rather than fixed.
See sample: `use-invariant-date-literals.good.al`.
See sample: [`use-invariant-date-literals.good.al`](use-invariant-date-literals.good.al).
## Anti Pattern
Building a fixed date by passing localized text such as `01/02/2025` to `Evaluate`. Detection signal: `Evaluate` converting a hard-coded or label-backed formatted string into a `Date`.
See sample: `use-invariant-date-literals.bad.al`.
See sample: [`use-invariant-date-literals.bad.al`](use-invariant-date-literals.bad.al).