PL-200 study materials
PL-200 study resources

Litware case app: form-scoped business rule and an 8-second form

PL-200 · Put your knowledge to work in context.

All case studies

Litware case app: form-scoped business rule and an 8-second form

Litware's case management model-driven app has one main Case form with 240 fields across 9 tabs and 11 subgrids, 8 of them on the first tab. Opening a case takes 8–12 seconds. A business rule on that form - scope set to the form, not the entity - makes Resolution Notes required and clears a field when Status = Resolved. Records created by an Azure integration through the Web API arrive with Status = Resolved and empty Resolution Notes several times a day. The app also has a custom 'Escalate' command that should appear only for members of the Escalation Team security role. All three issues must be fixed in two weeks without writing plug-in code.

1. Why does the business rule fail for API-created records, and what exactly do you change? What caveat do you disclose?

Read the worked answer

Scope is the bug. A rule scoped to a form only runs in that form's client context. The Web API integration never renders the form, so nothing evaluates the rule and the invalid record is accepted.

Change: open the business rule, set Scope = Entity (All Forms), and activate a new version. Entity-scoped rules execute server-side on create/update as well as in every form, so the resolution-notes requirement is enforced for API writes too.

Two things to verify while you are in there:

  • Every column the rule references must exist on the entity and, for the client behaviour, on the form; a condition on a column absent from the form behaves inconsistently.
  • Re-test the 'clears a field' action - an entity-scoped rule that sets a field runs on save and can overwrite integration-supplied values. If the integration deliberately sets that field, narrow the rule's condition.

Caveat to disclose: business rules do not run during bulk edit in the model-driven app. If the requirement is genuinely "no record can ever be Resolved without notes, by any path," that last gap needs a synchronous plug-in or real-time workflow - which is out of scope for the two-week window, so document it as a known residual risk rather than claiming full coverage.

2. How do you get the form from 8–12 seconds down to an acceptable load time, given you cannot change the data model in two weeks?

Read the worked answer

Attack what renders on open, not the data model.

  1. Measure first. Use the form's performance data and the browser network trace to confirm the subgrids are the cost (each is a separate query). Do not guess.
  2. Move subgrids off the first tab. Unified Interface loads the first tab eagerly and other tabs on demand. Leaving 8 subgrids on tab 1 means 8 queries before the user sees anything; relocating them to named tabs is the single biggest win and requires no code.
  3. Delete what nobody uses. 240 fields across 9 tabs almost certainly contains fields retired years ago. Removing them from the form (not the entity) reduces payload with zero data risk.
  4. Trim the subgrid views to 3–4 columns and ensure each has a supporting index/filtered view; an unfiltered subgrid over a large table is the classic 8-second form.
  5. Remove or defer synchronous JavaScript on OnLoad - a blocking Xrm.WebApi call in OnLoad serialises the whole load.
  6. Consider the timeline/notes control, which is expensive on records with many activities.

Prove the gain by measuring the same form again after each change; if the first tab still exceeds roughly 3 seconds, the next step is splitting the form into a lightweight main form plus a focused dialog for the heavy related data.

3. Describe how to make the 'Escalate' command appear only for Escalation Team members, and where you would additionally enforce it.

Read the worked answer

Visibility is UI; enforcement must be server-side.

  1. In the modern command designer (or the classic ribbon), edit the command and add an enable rule.
  2. The enable rule checks role membership via JavaScript using the user's role IDs:
function isEscalationMember() {
  const roles = Xrm.Utility.getGlobalContext().userSettings.securityRoles;
  return roles.indexOf("<escalation-role-guid>") > -1;
}
  1. Wire the rule to the command's EnableRule so the button is hidden or disabled for everyone else. Note that this is a client-side check - a determined user can call the same message another way.
  2. Enforce in the security model: the simplest robust answer is to give the Escalation Team role the privilege that the command requires (e.g., a custom 'Escalate' action or a Write on a field only they hold). If the command calls an action, secure the action's privilege so non-members get a privilege error even via the API.
  3. If the action must run with elevated rights, put it behind a flow triggered from the command, using a connection owned by a service account, and validate role membership at the start of the flow rather than trusting the button's visibility.

Do not report the work as done on the strength of the hidden button alone - say plainly that step 4 is what makes it secure.