Skill: dataverse-plugin-development
- typ: interní publikace agentem vytvořeného skillu
- vytvořil:
agent - created_at:
2026-05-10T20:47:30.557089+00:00 - patch_count:
6 - dostupné profily:
default - zdroj:
~/.hermes/skills/software-development/dataverse-plugin-development/SKILL.md
Dataverse / Dynamics 365 Plugin Development
Use this skill when creating, reviewing, or refactoring Microsoft Dynamics 365 / Dataverse plugins in C# using Microsoft.Xrm.Sdk.IPlugin.
Core pattern
- Prefer a reusable
PluginBase : IPluginthat owns the Dataverse entry pointExecute(IServiceProvider). - Put business logic in an override such as
ExecutePlugin(LocalPluginContext context). - Use a per-execution
LocalPluginContextto expose strongly typed SDK services: IPluginExecutionContextIOrganizationServiceFactoryITracingService- user-scoped
IOrganizationService - admin/SYSTEM
IOrganizationServiceonly when genuinely needed - Keep plugin classes stateless. Dataverse can cache and reuse plugin instances across executions/threads.
- Wrap unexpected errors into
InvalidPluginExecutionException; let intentionalInvalidPluginExecutionExceptionpass through unchanged. - Trace technical detail; put user-facing messages in
InvalidPluginExecutionException.
Validation helpers to include
Good base classes should provide helpers for:
RequireInputParameter<T>(name)TryGetInputParameter<T>(name)RequireTargetEntity(expectedEntityName)RequireTargetReference(expectedEntityName)GetPreImage(name = "PreImage")GetPostImage(name = "PostImage")EnsureMessage(expectedMessageName)EnsureStage(expectedStage)- safe
Trace(format, args)that never throws on null or bad format strings
Registration conventions
Common stage constants:
10= PreValidation20= PreOperation40= PostOperation
Use PreOperation when modifying the incoming Target so changes are persisted in the same transaction without an extra Update call.
Use images intentionally:
- Register pre-image alias
PreImagefor old values needed in Update/Delete validation. - Register post-image alias
PostImagefor values after platform processing. - Keep image attributes minimal for performance.
Post Update validation pattern
When validating a required field after Update (for example account.accountnumber):
- Remember
Targetcontains only changed attributes, so unchanged values may be absent. - Prefer a registered
PostImagealiasPostImagewith the required attribute. - Fall back to
IOrganizationService.Retrieve(entity, id, new ColumnSet(attribute))if the image is missing. - Throw
InvalidPluginExecutionExceptionwith the exact business message requested. - Do not add a blanket
Depth > 1early return for pure validators that do not write data; they cannot self-recursively trigger and should still validate updates initiated by other plugins/workflows. - If validation must run on every account update, leave Filtering Attributes empty; filtering on the required field only validates when that field changes.
User-specific workflow note
For Zico, when using Claude for this class of coding task, do not use Claude/Anthropic API. Orchestrate Claude Code through subscription/OAuth only, e.g. wrapper that launches env -u ANTHROPIC_API_KEY claude ..., then verify produced files and publish markdown results to Hermes WWW when requested.
When publishing a markdown result for code artifacts, embed the source code directly in fenced code blocks inside the markdown, not only as links to separate .cs files.
Templates and references
templates/PluginBase.cs— production-friendly base class scaffold withLocalPluginContext.templates/ExampleAccountPlugin.cs— sample Account Update / PreOperation plugin deriving from the base class.references/d365-plugin-base-claude-orchestration.md— session-specific notes from the first Claude Code orchestration run that produced the template.references/accountnumber-post-update-validator.md— post-update Account validator pattern:TargetvsPostImagevsRetrieve, exact exception message, filtering/depth pitfalls.
Verification checklist
- The code references
Microsoft.Xrm.Sdk/Microsoft.CrmSdk.CoreAssemblies. - The plugin class has a public parameterless constructor; optionally
(string unsecureConfig, string secureConfig). - No mutable execution state is stored on the plugin instance.
Targettype and logical name are validated.- Message and stage are either registered correctly or defensively checked.
- Tracing is present around major decisions and exception paths.
- Unexpected exceptions are wrapped in
InvalidPluginExecutionException. - Example custom fields are clearly marked as assumptions, not universal schema.