Operation Buttons

An operation button runs an operation the server registered — a custom API, a custom action, one of Dataverse's own messages, or code of your own — and shows only to the users it is registered for. The button asks the server once which operations the signed-in user may run, and checks each record it would send against what the user may do to it, so it doesn't offer what the server would refuse. The server still judges every request when it is sent.

Registering an operation

Register an operation in the server's Program.cs: AddOperationAccess for a Dataverse operation, AddOperationHandler for your own code. Inside AddPortalRole, WithOperationAccess and WithOperationHandler grant one to the role's holders. A registration says who may run the operation, the parameters a request may carry, the records they must point to and the outputs that come back.

  • ForEveryone(), ForSignedInUsers(), ForContactsMatching(fetchXml) and ForWebRoles(...) say who may run it; a role's registration is for the role's holders. Under Dataverse-native security, contacts hold web roles rather than portal roles, and a custom API is offered only to users whose security roles grant its execute privilege.
  • A request for your own code is judged exactly as a Dataverse operation's is: the handler sees only requests that passed, with the parameters the server sets filled in, and the caller sees only the outputs the registration returns.
  • Your own code can't share Dataverse's transaction, so a request for it is sent on its own: a batch that carries it with anything else is refused.
  • Security describes everything a registration can say.

OperationButton

Put an OperationButton where the operation belongs, naming the operation and the parameter its record goes in.

React Blazor
  • It is hidden from users who may not run the operation, and while the answer is on its way; set WhenNotAllowed (whenNotAllowed) to disable it instead. The answer is asked for once and kept while the app is open; a request the server refuses asks for it again.
  • The record goes in RecordParameter: Record, any record by reference, or else the record of the RecordContext the button sits in, once it is saved. The user must be able to act on it as the registration requires: a form's record says what the user may do to it, and a record named by reference is read for it.
  • On a form, a Dataverse operation on the form's record is sent in the form's own save, after its changes, so both are saved or neither, and the record is read back. Your own code runs after the form's changes are saved.
  • Parameters are sent with every request, and GetParametersAsync (getParameters) gathers more when the button is clicked, from a dialog, say; returning nothing cancels the click. ConfirmationMessage asks before the operation runs, and OnCompleted hands back its outputs.
  • Set its text with Label or its content, and its icon, tooltip and appearance as on any other button.

Example

The demo registers a few lines of its own code as an operation for everyone. Type a name and click the button: the server answers, and the page words the greeting.

React example Blazor example React TypeScript Razor
Say hello

OperationGridButton

In a grid's toolbar, OperationGridButton runs the operation once for each selected row, sending the row in RecordParameter, and then refreshes the grid. It is enabled while every selected row is one the user may act on, which each row says itself. A Dataverse operation's requests are sent in one transaction, so they all run or none do; your own code runs on one row at a time and stops at the first that fails.

React Blazor

Example: on each selected row

Select some accounts and click Check: the demo's own code reads each one and answers its name. Approve is granted only to a portal role no visitor holds, so it shows disabled.

React example Blazor example React TypeScript Razor
All Accounts
Sort
All Accounts
Page size 102050100
Sort
Account Name
Account Name
Type the company or business name.
Account Number
Account Number
Type an ID number or code for the account to quickly search and identify the account in system views.
Main Phone
Main Phone
Type the main phone number for this account.
Address 1: City
Address 1: City
Type the city for the primary address.
Annual Revenue
Annual Revenue
Type the annual revenue for the account, used as an indicator in financial performance analysis.
Primary Contact
Primary Contact
Choose the primary contact for the account to provide quick access to contact details.
Abernathy - MacGyverKTWSLQHY(491) 600-8029Tampa$15,959,059.84Bradford Kiehn
Abshire - Marks4EBO9F42(432) 879-3107Boston$14,635,260.82Archibald Bailey
Adams - TorphyK6VNNUCN(864) 842-2566Annapolis$4,567,299.55Merle Vandervort
Altenwerth, D'Amore and ManteF9MN5BAZ(125) 048-0015Gulfport$3,839,082.81Heidi Reichel
Ankunding and Sons92P2G0SF(603) 147-5429Fargo$32,724,448.89Fatima White
Balistreri, Heller and Murphy3Y0AF481(909) 808-9886New Haven$7,097,756.35Angie Kreiger
Balistreri, Steuber and SchultzFF5RCGXG(435) 761-0052Hattiesburg$35,943,517.75Jake Bogisich
Bartoletti LLCJBQ0L2O8(292) 573-7498Santa Fe$766,813.66Cecil Sipes
Bartoletti, Ratke and BeattyWZIDG7K2(267) 075-5978Portland$32,338,459.84Tabitha Morissette
Barton, Koepp and CroninTGAL5Y8F(821) 885-8434Norman$43,550,293.98Marc Dibbert
Bashirian - HamillZS1XZLDL(792) 135-0145Baltimore$15,916,182.51Alexie Dach
Bashirian - WeberOC5PYOJC(492) 789-5504Cranston$23,269,960.31Emmet Krajcik
Baumbach and SonsX8V8TZRX(670) 937-4364Ann Arbor$4,319,879.33Charity Sawayn
Baumbach, Maggio and TurnerV24ZA492(509) 251-9848Orlando$25,479,745.81Cali McClure
Beahan IncB9XXSIJM(262) 429-4179Sioux Falls$45,854,197.84Tressa Graham
Berge and SonsWO8OIGR6(165) 108-8947Topeka$40,560,550.52Delphine Jerde
Bergnaum GroupT3KB03RE(381) 148-7032Rapid City$32,406,150.23Dakota Ward
Bergstrom and SonsG99XNRDY(182) 902-0206Casper$48,880,601.83Grant Funk
Bergstrom, Bins and FlatleyJ1TXPJ9I(409) 160-0657Pittsburgh$21,005,421.54Blanche Gulgowski
Blanda - Terry4L8RSVL9(190) 468-0033Vancouver$33,567,160.56Fausto Pagac
Bode LLCF5IR66HK(386) 496-6921Detroit$1,800,033.15Kane Pollich
Bogisich, Mitchell and BalistreriPCVDL8PS(267) 567-6606Manchester$10,336,491.66Esperanza Luettgen
Borer - MohrLHI1SSVO(070) 539-8404Providence$36,092,236.14Emelia Murray
Botsford - Baumbach8JZK18K6(389) 188-6100Cranston$318,662.34Maria Runte
Botsford, Schroeder and KassulkeU39NNCOJ(960) 101-3753Sacramento$19,016,940.28Raphael Bergnaum
Boyer - SchaeferEFJQXML0(473) 115-3249Fort Wayne$48,601,111.30Moses Metz
Boyle, Zulauf and LakinXXRF6GXU(028) 071-4090Helena$31,856,728.91Federico Hamill
Brekke LLCUCLPTB19(795) 385-0349Norman$25,296,518.98Noemie Stracke
Brekke, Feeney and JohnsVMGNL1M7(203) 861-9656Charleston$13,632,447.58Kristin Koch
Brown, Rohan and MayerEMOSYGOI(479) 235-6497Fairbanks$49,780,735.02Phoebe Legros
Cassin, Kassulke and Schaefer5KSSVNW7(852) 978-3789Flagstaff$29,260,487.45Dedrick Thiel
Christiansen - MetzGSZJ1ODJ(183) 163-4723Reno$25,227,451.85Hattie Schuster
Cole, Tillman and LangworthY1JNB47Q(289) 893-2488Dover$13,838,171.56Jody Rohan
Connelly, Cassin and Ledner69QI6R89(507) 196-5103Wilmington$28,880,982.86Berneice Stracke
Considine Inc1ZGMEMAV(013) 094-8065Anchorage$6,796,633.66Guido Hagenes
Considine, Wilkinson and SpencerHK18ZLOO(772) 222-6147Jersey City$8,490,647.93Douglas Prosacco
Cormier - HettingerJFLKC0CK(508) 849-8368Tucson$14,771,052.63Nola Hand
Cremin - Hodkiewicz4D30N08W(757) 968-3487Fort Wayne$27,239,848.21America Harber
Cruickshank - PollichP3JT5LVY(048) 698-7364Santa Fe$32,195,480.36Joey Reilly
Cruickshank, Auer and SchoenTV06VSEA(516) 585-5831Sioux Falls$3,560,781.82Tiana Kiehn
Cummerata GroupAJYD1N4I(429) 577-7392Minneapolis$20,579,317.84Gustave Zboncak
Daniel LLCADF0WMN9(371) 118-7804Madison$49,497,674.02Francisco Smitham
Denesik, Skiles and Beier2ZMSATDW(716) 332-8853Louisville$25,958,417.48Dock Aufderhar
Dibbert LLC4WT0EDV0(343) 448-8435Huntington$24,379,660.89Elroy Leuschke
Dickinson IncC7SI8E20(429) 201-5173Dover$44,819,510.87Milton Ledner
Dietrich and SonsLAEDD52L(189) 560-2423Hartford$3,522,175.29Heath Kunde
Donnelly - Sanford8SW26RNC(738) 522-0182Fort Wayne$37,819,037.93Betsy King
Dooley - NitzscheNUCMFF7S(574) 958-0441Charleston$11,318,528.04Roman Dietrich
Durgan and SonsCKOSAHML(332) 942-8325Saint Paul$5,901,769.33Connor Marks
Ebert - WymanHJBQWXIR(753) 557-3136Los Angeles$15,782,605.89Zetta Nolan

Asking what the user may run

The buttons ask GET /api/permissions/operations, which answers for the signed-in user alone: every operation they may run, or just the ones you name, with what a request for each may carry and the records it must point to. Your own UI can ask the same through IOperationAccessCache or IPowerPortalsProService.GetOperationAccessForCurrentUserAsync on Blazor, and useOperationAccess or ppp.retrieveOperationAccessAsync on React.

React Blazor

OperationButton Class

Parameters

Name
Type
Default
Description
AppearanceButtonAppearance?
How the button looks.
BusyMessagestring?
What the overlay says while the operation runs; a general 'Working...' when not set.
ChildContentRenderFragment?
The button's content, in place of OperationButtonBase.Label.
ConfirmationMessagestring?
A question the user answers before the operation runs — 'Issue a refund for this invoice?' — or null to run it straight away.
ContextRecordContext?
The record context whose record the button sends. Not necessary if the button is placed inside a Components.RecordContext.
Disabledbool
False
Disables the button, whatever the user may run.
GetParametersAsyncFunc<Task<IReadOnlyDictionary<string, ColumnValueBase>>>?
Gathers parameters when the button is clicked — from a dialog, say — added to OperationButtonBase.Parameters. Returning null cancels the click. They are known only once clicked, so whether the user may run the operation is judged before then without them, and the server judges the request with them.
IconIcon?
An icon shown before the text.
Labelstring?
The button's text.
Operation*string
The operation's name, as it is registered.
ParametersIReadOnlyDictionary<string, ColumnValueBase>?
The parameters sent with every request, by name. A record parameter is a Models.LookupValue; the record it names must be one the user may act on as the operation's registration requires, or the button counts as not allowed.
RecordTableRecordReference?
The record sent in OperationButtonBase.RecordParameter, by reference. When not set, the record of the Components.RecordContext the button sits in (or OperationButton.Context) is sent, once saved.
RecordParameterstring?
The parameter the record is sent in — Target, say: an Components.OperationButton's OperationButton.Record or form record, each selected row of an Components.OperationGridButton.
RefreshRecordbool
True
Whether the form's record is read back once an operation run on its own — the host's code — has run on it, as it may have changed it. On by default. A Dataverse operation that rides the form's save is read back with the save, as on React.
Tooltipstring?
Shown when the pointer rests on the button.
WhenNotAllowedOperationButtonBehavior
Hide
What the button does where the user may not run the operation. Hidden by default.
Name: Appearance
Type: ButtonAppearance?
Description: How the button looks.
Name: BusyMessage
Type: string?
Description: What the overlay says while the operation runs; a general 'Working...' when not set.
Name: ChildContent
Type: RenderFragment?
Description: The button's content, in place of OperationButtonBase.Label.
Name: ConfirmationMessage
Type: string?
Description: A question the user answers before the operation runs — 'Issue a refund for this invoice?' — or null to run it straight away.
Name: Context
Type: RecordContext?
Description: The record context whose record the button sends. Not necessary if the button is placed inside a Components.RecordContext.
Name: Disabled
Type: bool
Default: False
Description: Disables the button, whatever the user may run.
Name: GetParametersAsync
Type: Func<Task<IReadOnlyDictionary<string, ColumnValueBase>>>?
Description: Gathers parameters when the button is clicked — from a dialog, say — added to OperationButtonBase.Parameters. Returning null cancels the click. They are known only once clicked, so whether the user may run the operation is judged before then without them, and the server judges the request with them.
Name: Icon
Type: Icon?
Description: An icon shown before the text.
Name: Label
Type: string?
Description: The button's text.
Name: Operation*
Type: string
Description: The operation's name, as it is registered.
Name: Parameters
Type: IReadOnlyDictionary<string, ColumnValueBase>?
Description: The parameters sent with every request, by name. A record parameter is a Models.LookupValue; the record it names must be one the user may act on as the operation's registration requires, or the button counts as not allowed.
Name: Record
Type: TableRecordReference?
Description: The record sent in OperationButtonBase.RecordParameter, by reference. When not set, the record of the Components.RecordContext the button sits in (or OperationButton.Context) is sent, once saved.
Name: RecordParameter
Type: string?
Description: The parameter the record is sent in — Target, say: an Components.OperationButton's OperationButton.Record or form record, each selected row of an Components.OperationGridButton.
Name: RefreshRecord
Type: bool
Default: True
Description: Whether the form's record is read back once an operation run on its own — the host's code — has run on it, as it may have changed it. On by default. A Dataverse operation that rides the form's save is read back with the save, as on React.
Name: Tooltip
Type: string?
Description: Shown when the pointer rests on the button.
Name: WhenNotAllowed
Type: OperationButtonBehavior
Default: Hide
Description: What the button does where the user may not run the operation. Hidden by default.

Events

Name
Type
Description
OnCompletedEventCallback<OperationCompletedEventArgs>
Raised once the operation has run, with what it answered.
OnErrorEventCallback<Exception>
Raised when the operation fails, in place of the error dialog the button otherwise shows.
Name: OnCompleted
Type: EventCallback<OperationCompletedEventArgs>
Description: Raised once the operation has run, with what it answered.
Name: OnError
Type: EventCallback<Exception>
Description: Raised when the operation fails, in place of the error dialog the button otherwise shows.
React Blazor

OperationGridButton Class

Parameters

Name
Type
Default
Description
AppearanceButtonAppearance?
How the button looks.
BusyMessagestring?
What the overlay says while the operation runs; a general 'Working...' when not set.
ConfirmationMessagestring?
A question the user answers before the operation runs — 'Issue a refund for this invoice?' — or null to run it straight away.
Disabledbool
False
Disables the button, whatever the user may run.
GetParametersAsyncFunc<Task<IReadOnlyDictionary<string, ColumnValueBase>>>?
Gathers parameters when the button is clicked — from a dialog, say — added to OperationButtonBase.Parameters. Returning null cancels the click. They are known only once clicked, so whether the user may run the operation is judged before then without them, and the server judges the request with them.
IconIcon?
An icon shown before the text.
Labelstring?
The button's text.
Operation*string
The operation's name, as it is registered.
ParametersIReadOnlyDictionary<string, ColumnValueBase>?
The parameters sent with every request, by name. A record parameter is a Models.LookupValue; the record it names must be one the user may act on as the operation's registration requires, or the button counts as not allowed.
RecordParameterstring?
The parameter the record is sent in — Target, say: an Components.OperationButton's OperationButton.Record or form record, each selected row of an Components.OperationGridButton.
Tooltipstring?
Shown when the pointer rests on the button.
VisibilityBehaviorGridButtonBehavior?
When the button is shown, by the selection. With a record parameter, for one or more selected rows; without, always.
WhenNotAllowedOperationButtonBehavior
Hide
What the button does where the user may not run the operation. Hidden by default.
Name: Appearance
Type: ButtonAppearance?
Description: How the button looks.
Name: BusyMessage
Type: string?
Description: What the overlay says while the operation runs; a general 'Working...' when not set.
Name: ConfirmationMessage
Type: string?
Description: A question the user answers before the operation runs — 'Issue a refund for this invoice?' — or null to run it straight away.
Name: Disabled
Type: bool
Default: False
Description: Disables the button, whatever the user may run.
Name: GetParametersAsync
Type: Func<Task<IReadOnlyDictionary<string, ColumnValueBase>>>?
Description: Gathers parameters when the button is clicked — from a dialog, say — added to OperationButtonBase.Parameters. Returning null cancels the click. They are known only once clicked, so whether the user may run the operation is judged before then without them, and the server judges the request with them.
Name: Icon
Type: Icon?
Description: An icon shown before the text.
Name: Label
Type: string?
Description: The button's text.
Name: Operation*
Type: string
Description: The operation's name, as it is registered.
Name: Parameters
Type: IReadOnlyDictionary<string, ColumnValueBase>?
Description: The parameters sent with every request, by name. A record parameter is a Models.LookupValue; the record it names must be one the user may act on as the operation's registration requires, or the button counts as not allowed.
Name: RecordParameter
Type: string?
Description: The parameter the record is sent in — Target, say: an Components.OperationButton's OperationButton.Record or form record, each selected row of an Components.OperationGridButton.
Name: Tooltip
Type: string?
Description: Shown when the pointer rests on the button.
Name: VisibilityBehavior
Type: GridButtonBehavior?
Description: When the button is shown, by the selection. With a record parameter, for one or more selected rows; without, always.
Name: WhenNotAllowed
Type: OperationButtonBehavior
Default: Hide
Description: What the button does where the user may not run the operation. Hidden by default.

Events

Name
Type
Description
OnCompletedEventCallback<OperationCompletedEventArgs>
Raised once the operation has run, with what it answered.
OnErrorEventCallback<Exception>
Raised when the operation fails, in place of the error dialog the button otherwise shows.
Name: OnCompleted
Type: EventCallback<OperationCompletedEventArgs>
Description: Raised once the operation has run, with what it answered.
Name: OnError
Type: EventCallback<Exception>
Description: Raised when the operation fails, in place of the error dialog the button otherwise shows.