dataverse
Dataverse Development
Expert guidance for Dataverse Web API, C# plugin development, custom APIs, security model, and data operations.
Triggers
Use this skill when you see:
- dataverse, common data service, cds
- dataverse web api, odata, fetchxml
- dataverse plugin, iplugin, iorganizationservice
- custom api, dataverse security, security role
- early bound, modelbuilder, dataverse sdk
Instructions
Web API (OData) Patterns
# Retrieve records with select and filter
GET [org]/api/data/v9.2/accounts?$select=name,revenue&$filter=revenue gt 1000000&$top=10
Authorization: Bearer {token}
Prefer: odata.include-annotations="*"
# Retrieve with expand (related records)
GET [org]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)?$select=name&$expand=contact_customer_accounts($select=fullname,emailaddress1;$top=5)
# Create a record
POST [org]/api/data/v9.2/accounts
Content-Type: application/json
{
"name": "Contoso Ltd",
"revenue": 5000000,
"primarycontactid@odata.bind": "/contacts(00000000-0000-0000-0000-000000000002)"
}
# Update a record
PATCH [org]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)
Content-Type: application/json
If-Match: *
{
"name": "Contoso Ltd (Updated)",
"revenue": 6000000
}
# Delete a record
DELETE [org]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)
# Batch request
POST [org]/api/data/v9.2/$batch
Content-Type: multipart/mixed;boundary=batch_boundary
--batch_boundary
Content-Type: application/http
Content-Transfer-Encoding: binary
GET accounts?$select=name&$top=5 HTTP/1.1
Accept: application/json
--batch_boundary--
FetchXML Queries
<!-- Aggregation query -->
<fetch aggregate="true">
<entity name="opportunity">
<attribute name="estimatedvalue" alias="total_value" aggregate="sum" />
<attribute name="ownerid" alias="owner" groupby="true" />
<filter>
<condition attribute="statecode" operator="eq" value="0" />
<condition attribute="estimatedclosedate" operator="this-year" />
</filter>
</entity>
</fetch>
<!-- Linked entities with outer join -->
<fetch>
<entity name="account">
<attribute name="name" />
<attribute name="revenue" />
<link-entity name="contact" from="parentcustomerid" to="accountid" link-type="outer" alias="c">
<attribute name="fullname" />
<attribute name="emailaddress1" />
</link-entity>
<filter>
<condition attribute="statecode" operator="eq" value="0" />
</filter>
<order attribute="name" />
</entity>
</fetch>
Plugin Development (C#)
// Plugin class implementing IPlugin
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
namespace Contoso.Plugins
{
public class AccountPreCreate : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
// Obtain services from the service provider
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var service = serviceFactory.CreateOrganizationService(context.UserId);
var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
try
{
// Validate the target entity
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity target)
{
tracingService.Trace("AccountPreCreate: Processing {0}", target.LogicalName);
// Business logic: auto-set account number
if (!target.Contains("accountnumber"))
{
var query = new QueryExpression("account")
{
ColumnSet = new ColumnSet("accountnumber"),
TopCount = 1,
Orders = { new OrderExpression("createdon", OrderType.Descending) }
};
var results = service.RetrieveMultiple(query);
var nextNumber = results.Entities.Count > 0
? int.Parse(results.Entities[0].GetAttributeValue<string>("accountnumber") ?? "0") + 1
: 1001;
target["accountnumber"] = nextNumber.ToString();
tracingService.Trace("Set account number to {0}", nextNumber);
}
}
}
catch (Exception ex)
{
tracingService.Trace("AccountPreCreate Error: {0}", ex.ToString());
throw new InvalidPluginExecutionException(
"An error occurred in the Account Pre-Create plugin.", ex);
}
}
}
}
Plugin Registration
# Initialize plugin project
pac plugin init
# Project structure:
# MyPlugin/
# ├── MyPlugin.csproj
# ├── Plugin1.cs # IPlugin implementation
# └── PluginBase.cs # Optional base class
# Build and register
dotnet build
# Use Plugin Registration Tool or pac CLI to register steps
# Plugin Registration Tool steps:
# 1. Register assembly (DLL)
# 2. Register step (message, entity, stage, mode)
# 3. Register image (pre/post entity images if needed)
Custom APIs
// Custom API plugin
namespace Contoso.Plugins
{
public class CalculateDiscount : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Read request parameters
var accountId = (string)context.InputParameters["AccountId"];
var orderTotal = (decimal)context.InputParameters["OrderTotal"];
// Business logic
decimal discountRate = orderTotal > 10000 ? 0.15m : 0.05m;
decimal discountedTotal = orderTotal * (1 - discountRate);
// Set response parameters
context.OutputParameters["DiscountRate"] = discountRate;
context.OutputParameters["DiscountedTotal"] = discountedTotal;
}
}
}
# Call custom API via Web API
POST [org]/api/data/v9.2/contoso_CalculateDiscount
Content-Type: application/json
{
"AccountId": "00000000-0000-0000-0000-000000000001",
"OrderTotal": 15000.00
}
Early-Bound Types
# Generate early-bound entity classes
pac modelbuilder build
# Configuration in builderSettings.json:
# {
# "entities": ["account", "contact", "opportunity"],
# "generateActions": true,
# "namespaces": { "account": "Contoso.DataModel" }
# }
Security Model
Security Layers:
1. Security Roles - Define table-level CRUD privileges
2. Privilege Depth - User / Business Unit / Parent-Child BU / Organization
3. Column Security - Restrict access to specific columns
4. Row-Level Sharing - Share individual records with users/teams
5. Teams - Owner teams, Access teams, AAD group teams
6. Field Masking - Mask sensitive data in columns
Role Privilege Matrix:
┌───────────────┬────────┬──────┬────────┬────────┬────────┐
│ Entity │ Create │ Read │ Update │ Delete │ Append │
├───────────────┼────────┼──────┼────────┼────────┼────────┤
│ Account │ BU │ Org │ BU │ User │ BU │
│ Contact │ BU │ Org │ BU │ User │ BU │
│ Opportunity │ User │ BU │ User │ None │ User │
└───────────────┴────────┴──────┴────────┴────────┴────────┘
Depth: User < BU < Parent-Child BU < Organization
Best Practices
| Practice | Description |
|---|---|
| Web API pagination | Use @odata.nextLink for large result sets; default page size is 5000 |
| Select columns | Always use $select to retrieve only needed columns |
| Plugin idempotency | Design plugins to produce the same result if executed multiple times |
| Tracing | Use ITracingService extensively for debugging in plugin trace logs |
| Pre vs Post | Use pre-operation for validation/modification, post-operation for side effects |
| Async plugins | Register long-running logic as async to avoid blocking the user |
| Early-bound | Use pac modelbuilder build for type-safe entity access in plugins |
| Least privilege | Grant minimum required security role privileges |
Common Workflows
New Plugin Development
pac plugin initto scaffold project- Implement
IPlugin.Executewith business logic - Build and test locally
- Register assembly with Plugin Registration Tool
- Register step (message, entity, stage)
- Test in Dataverse environment
- Add to solution for ALM
Web API Integration
- Register Azure AD app with Dataverse permissions
- Obtain OAuth 2.0 token (client credentials or auth code)
- Use
$select,$filter,$expandfor efficient queries - Handle pagination with
@odata.nextLink - Use batch operations for bulk operations
- Implement retry logic for throttling (429 responses)
More from housegarofalo/claude-code-base
mqtt-iot
Configure MQTT brokers (Mosquitto, EMQX) for IoT messaging, device communication, and smart home integration. Manage topics, QoS levels, authentication, and bridging. Use when setting up IoT messaging, smart home communication, or device-to-cloud connectivity. (project)
22devops-engineer-agent
Infrastructure and DevOps specialist. Manages Docker, Kubernetes, CI/CD pipelines, and cloud deployments. Expert in GitHub Actions, Azure DevOps, Terraform, and container orchestration. Use for deployment automation, infrastructure setup, or CI/CD optimization.
6postgresql
Design, optimize, and manage PostgreSQL databases. Covers indexing, pgvector for AI embeddings, JSON operations, full-text search, and query optimization. Use when working with PostgreSQL, database design, or building data-intensive applications.
6home-assistant
Ultimate Home Assistant skill - complete administration, wireless protocols (Zigbee/ZHA/Z2M, Z-Wave JS, Thread, Matter), ESPHome device building, advanced troubleshooting, performance optimization, security hardening, custom integration development, and professional dashboard design. Covers configuration, REST API, automation debugging, database optimization, SSL/TLS, Jinja2 templating, and HACS custom cards. Use for any HA task.
6testing
Comprehensive testing skill covering unit, integration, and E2E testing with pytest, Jest, Cypress, and Playwright. Use for writing tests, improving coverage, debugging test failures, and setting up testing infrastructure.
5react-typescript
Build modern React applications with TypeScript. Covers React 18+ patterns, hooks, component architecture, state management (Zustand, Redux Toolkit), server components, and best practices. Use for React development, TypeScript integration, component design, and frontend architecture.
5