Un botón de operación ejecuta una operación registrada por el servidor — una API personalizada, una acción personalizada, uno de los mensajes propios de Dataverse o código propio — y solo se muestra a los usuarios para los que está registrado. El botón pregunta una vez al servidor qué operaciones puede ejecutar el usuario iniciado sesión, y comprueba cada registro que enviarÃa con lo que el usuario podrÃa hacerle, para no ofrecer lo que el servidor rechazarÃa. El servidor sigue juzgando cada solicitud cuando se envÃa.
Registra una operación en el servidor Program.cs: AddOperationAccess para una operación Dataverse, AddOperationHandler para tu propio código. Dentro AddPortalRolede , WithOperationAccess y WithOperationHandler concede una a los titulares del rol. Un registro indica quién puede ejecutar la operación, los parámetros que puede llevar una solicitud, los registros a los que deben apuntar y las salidas que regresan.
// Program.cs (the server)
// Una API personalizada para los titulares del rol de facturación, en una factura pueden cambiar
builder.Services.AddPortalRole("Billing", role => role
.WithOperationAccess("ppp_IssueRefund", o => o
.OnRecord("Target", TableSecurityPermission.Write)
.AcceptingParameters("Amount")
.ReturningOutputs("RefundId")));
// Tu propio código, para cualquier usuario que haya iniciado sesión, en un presupuesto que puedan leer
builder.Services.AddOperationHandler<SendQuoteHandler>("SendQuote", o => o
.ForSignedInUsers()
.OnRecord("Quote", TableSecurityPermission.Read)
.ReturningOutputs("SentTo"));
public sealed class SendQuoteHandler(IQuoteMailer mailer) : IPortalOperationHandler
{
public async Task<IReadOnlyDictionary<string, ColumnValueBase?>?> ExecuteAsync(
PortalOperationContext context, CancellationToken cancellationToken)
{
var quote = context.GetParameter<LookupValue>("Quote")!;
var sentTo = await mailer.SendAsync(quote.Value!.Value, cancellationToken);
return new Dictionary<string, ColumnValueBase?> { ["SentTo"] = new StringValue { Value = sentTo } };
}
}
ForEveryone(), ForSignedInUsers(), ForContactsMatching(fetchXml) y ForWebRoles(...) indican quién puede ejecutarlo; el registro de un rol es para los titulares del puesto. Bajo la seguridad nativa de Dataverse, los contactos tienen roles web en lugar de portales, y una API personalizada solo se ofrece a los usuarios cuyos roles de seguridad otorgan su privilegio de ejecución.Pon un OperationButton lugar donde debe estar la operación, nombrando la operación y el parámetro en el que va su registro.
<RecordContext table="invoice" queryParameterName="id">
<OperationButton
operation="ppp_IssueRefund"
recordParameter="Target"
label="Issue refund"
icon={<Money20Regular />}
confirmationMessage="Issue a refund for this invoice?"
getParameters={askForAmount}
onCompleted={({ outputs }) => showRefund(outputs.RefundId)}
/>
</RecordContext><RecordContext TableName="invoice" QueryParameterName="id">
<OperationButton Operation="ppp_IssueRefund"
RecordParameter="Target"
Label="Issue refund"
Icon="@(new Icons.Regular.Size20.Money())"
ConfirmationMessage="Issue a refund for this invoice?"
GetParametersAsync="AskForAmountAsync"
OnCompleted="ShowRefund" />
</RecordContext>WhenNotAllowed (whenNotAllowed) para desactivarla en su lugar. La respuesta se pide una vez y se guarda mientras la aplicación está abierta; una solicitud que el servidor rechaza la solicita de nuevo.RecordParameteren : Record, cualquier registro por referencia, o bien el registro del RecordContext botón se queda en el botón una vez guardado. El usuario debe poder actuar en consecuencia según lo requiera el registro: el registro de un formulario indica lo que el usuario puede hacer con él, y se lee un registro nombrado por referencia para él.Parameters se envÃan con cada petición, y GetParametersAsync (getParameters) recoge más cuando se pulsa el botón, por ejemplo, desde un diálogo, por ejemplo; al no devolver nada cancela el clic. ConfirmationMessage pregunta antes de que se ejecute la operación y OnCompleted devuelve sus salidas.Label o su contenido, y su icono, descripción emergente y apariencia como en cualquier otro botón.La demo registra unas lÃneas de su propio código como operación para todos. Escribe un nombre y haz clic en el botón: el servidor responde y la página dice el saludo.
En la barra de herramientas de una cuadrÃcula, OperationGridButton ejecuta la operación una vez por cada fila seleccionada, enviando la fila en RecordParameter, y luego actualiza la cuadrÃcula. Está habilitada mientras cada fila seleccionada es una sobre la que el usuario puede actuar, que cada fila dice por sà misma. Las peticiones de una operación de Dataverse se envÃan en una sola transacción, asà que todas se ejecutan o ninguna; tu propio código se ejecuta en una fila a la vez y se detiene en la primera que falla.
<MainGrid tableName="invoice">
<GridToolbarItems>
<OperationGridButton
operation="ppp_ApproveInvoice"
recordParameter="Target"
label="Approve"
whenNotAllowed="disable"
/>
</GridToolbarItems>
</MainGrid><MainGrid TableName="invoice">
<ToolbarItems>
<OperationGridButton Operation="ppp_ApproveInvoice"
RecordParameter="Target"
Label="Approve"
WhenNotAllowed="OperationButtonBehavior.Disable" />
</ToolbarItems>
</MainGrid>Selecciona algunas cuentas y haz clic en Comprobar: el propio código de la demo lee cada una y responde a su nombre. Aprobación solo se concede a un rol de portal que ningún visitante posee, asà que aparece desactivado.
Nombre de la cuenta
Nombre de la cuenta Escriba el nombre de la empresa o negocio. | Número de cuenta Número de cuenta Escriba un número de identificación o código para la cuenta para buscar e identificar rápidamente la cuenta en las vistas del sistema. | Teléfono principal Teléfono principal Escriba el número de teléfono principal de esta cuenta. | Dirección 1: Ciudad Dirección 1: Ciudad Escriba la ciudad para la dirección principal. | Ingresos anuales Ingresos anuales Escriba los ingresos anuales de la cuenta, que se utilizan como indicador en el análisis de rendimiento financiero. | Contacto principal Contacto principal Elija el contacto principal de la cuenta para proporcionar acceso rápido a los detalles de contacto. | |
|---|---|---|---|---|---|---|
| Abernathy - MacGyver | KTWSLQHY | (491) 600-8029 | Tampa | $15.959.059,84 | Bradford Kiehn | |
| Abshire - Marks | 4EBO9F42 | (432) 879-3107 | Boston | $14.635.260,82 | Archibald Bailey | |
| Adams - Torphy | K6VNNUCN | (864) 842-2566 | Annapolis | $4.567.299,55 | Merle Vandervort | |
| Altenwerth, D'Amore and Mante | F9MN5BAZ | (125) 048-0015 | Gulfport | $3.839.082,81 | Heidi Reichel | |
| Ankunding and Sons | 92P2G0SF | (603) 147-5429 | Fargo | $32.724.448,89 | Fatima White | |
| Balistreri, Heller and Murphy | 3Y0AF481 | (909) 808-9886 | New Haven | $7.097.756,35 | Angie Kreiger | |
| Balistreri, Steuber and Schultz | FF5RCGXG | (435) 761-0052 | Hattiesburg | $35.943.517,75 | Jake Bogisich | |
| Bartoletti LLC | JBQ0L2O8 | (292) 573-7498 | Santa Fe | $766.813,66 | Cecil Sipes | |
| Bartoletti, Ratke and Beatty | WZIDG7K2 | (267) 075-5978 | Portland | $32.338.459,84 | Tabitha Morissette | |
| Barton, Koepp and Cronin | TGAL5Y8F | (821) 885-8434 | Norman | $43.550.293,98 | Marc Dibbert | |
| Bashirian - Hamill | ZS1XZLDL | (792) 135-0145 | Baltimore | $15.916.182,51 | Alexie Dach | |
| Bashirian - Weber | OC5PYOJC | (492) 789-5504 | Cranston | $23.269.960,31 | Emmet Krajcik | |
| Baumbach and Sons | X8V8TZRX | (670) 937-4364 | Ann Arbor | $4.319.879,33 | Charity Sawayn | |
| Baumbach, Maggio and Turner | V24ZA492 | (509) 251-9848 | Orlando | $25.479.745,81 | Cali McClure | |
| Beahan Inc | B9XXSIJM | (262) 429-4179 | Sioux Falls | $45.854.197,84 | Tressa Graham | |
| Berge and Sons | WO8OIGR6 | (165) 108-8947 | Topeka | $40.560.550,52 | Delphine Jerde | |
| Bergnaum Group | T3KB03RE | (381) 148-7032 | Rapid City | $32.406.150,23 | Dakota Ward | |
| Bergstrom and Sons | G99XNRDY | (182) 902-0206 | Casper | $48.880.601,83 | Grant Funk | |
| Bergstrom, Bins and Flatley | J1TXPJ9I | (409) 160-0657 | Pittsburgh | $21.005.421,54 | Blanche Gulgowski | |
| Blanda - Terry | 4L8RSVL9 | (190) 468-0033 | Vancouver | $33.567.160,56 | Fausto Pagac | |
| Bode LLC | F5IR66HK | (386) 496-6921 | Detroit | $1.800.033,15 | Kane Pollich | |
| Bogisich, Mitchell and Balistreri | PCVDL8PS | (267) 567-6606 | Manchester | $10.336.491,66 | Esperanza Luettgen | |
| Borer - Mohr | LHI1SSVO | (070) 539-8404 | Providence | $36.092.236,14 | Emelia Murray | |
| Botsford - Baumbach | 8JZK18K6 | (389) 188-6100 | Cranston | $318.662,34 | Maria Runte | |
| Botsford, Schroeder and Kassulke | U39NNCOJ | (960) 101-3753 | Sacramento | $19.016.940,28 | Raphael Bergnaum | |
| Boyer - Schaefer | EFJQXML0 | (473) 115-3249 | Fort Wayne | $48.601.111,30 | Moses Metz | |
| Boyle, Zulauf and Lakin | XXRF6GXU | (028) 071-4090 | Helena | $31.856.728,91 | Federico Hamill | |
| Brekke LLC | UCLPTB19 | (795) 385-0349 | Norman | $25.296.518,98 | Noemie Stracke | |
| Brekke, Feeney and Johns | VMGNL1M7 | (203) 861-9656 | Charleston | $13.632.447,58 | Kristin Koch | |
| Brown, Rohan and Mayer | EMOSYGOI | (479) 235-6497 | Fairbanks | $49.780.735,02 | Phoebe Legros | |
| Cassin, Kassulke and Schaefer | 5KSSVNW7 | (852) 978-3789 | Flagstaff | $29.260.487,45 | Dedrick Thiel | |
| Christiansen - Metz | GSZJ1ODJ | (183) 163-4723 | Reno | $25.227.451,85 | Hattie Schuster | |
| Cole, Tillman and Langworth | Y1JNB47Q | (289) 893-2488 | Dover | $13.838.171,56 | Jody Rohan | |
| Connelly, Cassin and Ledner | 69QI6R89 | (507) 196-5103 | Wilmington | $28.880.982,86 | Berneice Stracke | |
| Considine Inc | 1ZGMEMAV | (013) 094-8065 | Anchorage | $6.796.633,66 | Guido Hagenes | |
| Considine, Wilkinson and Spencer | HK18ZLOO | (772) 222-6147 | Jersey City | $8.490.647,93 | Douglas Prosacco | |
| Cormier - Hettinger | JFLKC0CK | (508) 849-8368 | Tucson | $14.771.052,63 | Nola Hand | |
| Cremin - Hodkiewicz | 4D30N08W | (757) 968-3487 | Fort Wayne | $27.239.848,21 | America Harber | |
| Cruickshank - Pollich | P3JT5LVY | (048) 698-7364 | Santa Fe | $32.195.480,36 | Joey Reilly | |
| Cruickshank, Auer and Schoen | TV06VSEA | (516) 585-5831 | Sioux Falls | $3.560.781,82 | Tiana Kiehn | |
| Cummerata Group | AJYD1N4I | (429) 577-7392 | Minneapolis | $20.579.317,84 | Gustave Zboncak | |
| Daniel LLC | ADF0WMN9 | (371) 118-7804 | Madison | $49.497.674,02 | Francisco Smitham | |
| Denesik, Skiles and Beier | 2ZMSATDW | (716) 332-8853 | Louisville | $25.958.417,48 | Dock Aufderhar | |
| Dibbert LLC | 4WT0EDV0 | (343) 448-8435 | Huntington | $24.379.660,89 | Elroy Leuschke | |
| Dickinson Inc | C7SI8E20 | (429) 201-5173 | Dover | $44.819.510,87 | Milton Ledner | |
| Dietrich and Sons | LAEDD52L | (189) 560-2423 | Hartford | $3.522.175,29 | Heath Kunde | |
| Donnelly - Sanford | 8SW26RNC | (738) 522-0182 | Fort Wayne | $37.819.037,93 | Betsy King | |
| Dooley - Nitzsche | NUCMFF7S | (574) 958-0441 | Charleston | $11.318.528,04 | Roman Dietrich | |
| Durgan and Sons | CKOSAHML | (332) 942-8325 | Saint Paul | $5.901.769,33 | Connor Marks | |
| Ebert - Wyman | HJBQWXIR | (753) 557-3136 | Los Angeles | $15.782.605,89 | Zetta Nolan |
Los botones preguntan GET /api/permissions/operations, lo que responde solo para el usuario iniciado sesión: cada operación que pueda ejecutar, o solo las que nombras, con lo que puede llevar una solicitud para cada una y los registros a los que debe apuntar. Tu propia interfaz puede preguntar lo mismo a través IOperationAccessCache de Blazor o IPowerPortalsProService.GetOperationAccessForCurrentUserAsync useOperationAccess ppp.retrieveOperationAccessAsync en React.