Dverse.Sdk 0.1.0-ci.100

This is a prerelease version of Dverse.Sdk.
dotnet add package Dverse.Sdk --version 0.1.0-ci.100
                    
NuGet\Install-Package Dverse.Sdk -Version 0.1.0-ci.100
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Dverse.Sdk" Version="0.1.0-ci.100" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Dverse.Sdk" Version="0.1.0-ci.100" />
                    
Directory.Packages.props
<PackageReference Include="Dverse.Sdk" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Dverse.Sdk --version 0.1.0-ci.100
                    
#r "nuget: Dverse.Sdk, 0.1.0-ci.100"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Dverse.Sdk@0.1.0-ci.100
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Dverse.Sdk&version=0.1.0-ci.100&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Dverse.Sdk&version=0.1.0-ci.100&prerelease
                    
Install as a Cake Tool

dverse

Declarative deployment + SDK for Microsoft Dataverse / Dynamics 365 plugins. dverse replaces spkl-style imperative registration with a Terraform-like plan/apply model, and replaces hand-written plugin boilerplate with source-generated code.

Dataverse online only. dverse authenticates via Microsoft Entra ID (Azure.Identity) and always registers plugins in the sandbox — there is no on-premises / IFD support and none is planned for v1.

You write only this, in a plain SDK-style csproj:

using Dverse;
using Dverse.Model;

public partial class AccountPlugins
{
    [Step(typeof(Account), Msg.Update, Stage.PreOperation,
        Filtering = new[] { Account.Cols.CreditLimit })]
    public void BlockCreditLimitDowngrade(IStepContext<Account> ctx)
    {
        if (ctx.Target.CreditLimit < ctx.PreImage.CreditLimit)
            throw ctx.Fail("Credit limits can't be lowered.");
    }
}

Then run dotnet build -t:Deploy. Everything else is generated or computed:

  • the IPlugin entry class and the embedded context runtime (no base classes, no runtime DLL, no ILMerge),
  • the pre-image registration — columns inferred from your code (ctx.PreImage.CreditLimit above ⇒ a pre-image with exactly creditlimit); escapes are compile errors, never a silent "all columns",
  • the registration manifest, diffed field-by-field against the live environment.

A no-op deploy performs zero writes in ~5 read round trips. dverse plan shows exactly what would change (--json for machines, exit code 0 = clean / 2 = changes pending) — put it in CI and never let an environment drift again.

Feature overview

Feature How
Early-bound models entities declared once in dataverse.yaml; plan/apply refresh dataverse.snapshot.json automatically (with a schema diff); a source generator emits entity classes, Cols constants, and optionset enums in-memory — no generated .cs files on disk
Plugin steps [Step(typeof(Account), Msg.Update, Stage.PreOperation, ...)] on a plain method taking IStepContext<Account>
Images Inferred from ctx.PreImage.X / ctx.PostImage.X access; explicit [Image(...)] as the escape hatch
Custom APIs [CustomApi("dverse_Reverse")] on a method with record request/response types; parameters sync automatically; typed callers are generated
Computed columns [Derive(Account.Cols.Description)] on a pure static method — compiles to coalesced, dependency-ordered Create/Update steps with inferred filtering
Real-time rollups [Rollup(Account.Cols.OpenBalance)] over Children<Contact> — the Where/aggregate expression compiles to one server-side FetchXML aggregate per affected parent, with reparenting (old + new parent) handled via an inferred pre-image
Web resources a webresources: entry in dataverse.yaml — built (e.g. esbuild), content-hash diffed, published in one PublishXml; dverse webresources pull adopts existing ones
PCF controls dverse pcf init scaffolds the standard pcf-scripts project; a pcf: entry in dataverse.yaml deploys every built control via a staged solution import — hash-diffed, so an unchanged control is zero writes
Code signing dverse sign init creates the code-signing certificate; a signing: entry in dataverse.yaml Authenticode-signs every assembly before upload — in-process, cross-platform, no signtool, and deterministic so a no-op deploy stays zero writes
Managed identity a managedIdentity: entry in dataverse.yaml creates and binds the managedidentity row so plugins reach Azure with no stored credentials (ctx.ManagedIdentity); dverse sign info prints the exact Azure federated credential to create for your certificate
Command-bar buttons [Command(typeof(Account), "Recalculate", Confirm = …, Progress = …, Success = "{response.Count} done", Refresh = Refresh.Form)] next to a [CustomApi] — the button, its JavaScript and its registration are generated; conditions (EnableWhenNotEmpty, RequireSelection, …) compile to a classic ribbon rule automatically
Modern commands a commands: entry in dataverse.yaml — appaction rows declared in YAML with a real field-level diff, so a changed label is one PATCH of one column; pruned by publisher prefix
Classic ribbons a ribbons: entry in dataverse.yaml — committed RibbonDiffXml per entity plus the application ribbon, diffed per element against the platform's decomposed storage, deployed by staged solution import
Schema & data a schema: entry declares tables, columns, option sets and relationships; seed: upserts reference rows; dverse schema adopt captures what already exists
Forms, views & apps committed formxml / savedquery / app-module fragments (dverse forms pull, dverse views pull), converged and published in the same single PublishXml
Deployment dverse plan / dverse apply (or dotnet build -t:Plan / -t:Deploy): field-level diff, sha256 assembly-upload skip, stale components pruned automatically, source versions auto-bumped when content changes (assembly revision / PCF patch)
Guard rails 42 compile-time diagnostics (DVERSE0xx): invalid stage/mode combos, pre-image on Create, filtering on unsupported messages, duplicate keys, impure derives, …

Getting started

The five-minute version

# 1. install the CLI (or run it from source: dotnet run --project src/Dverse.Cli --)
dotnet tool install --global Dverse.Cli --prerelease
dverse version   # the installed package version, e.g. 0.1.0-ci.89 (+ the commit it was built from)

# 2. in your plugin repo: describe your environments (no secrets — this file is committed)
cat > dataverse.yaml <<'EOF'
default: dev
environments:
  dev:
    url: https://yourorg.crm.dynamics.com
    solution: yoursolution
    prefix: your
EOF

# 3. sign in once (device code; later runs are silent)
dverse auth login
dverse whoami

# 4. declare the entities once in dataverse.yaml:
#      model:
#        entities: [account, contact]
#    plan/apply keep the model snapshot fresh automatically from then on

# 5. deploy (from the plugin project directory: builds, diffs, applies)
dverse apply
# ... or preview first / via MSBuild:
dverse plan
dotnet build -t:Deploy

Architecture in one paragraph

Plugins target net462 and reference exactly one package, Dverse.Sdk (attributes + source generators + MSBuild targets). The generators are pure: metadata comes exclusively from the committed dataverse.snapshot.json, so builds are reproducible and CI needs no Dataverse connection. The registration manifest is emitted as an inactive preprocessor block — it contributes zero IL, so a registration-only change (a rank, a filter column) never changes the assembly hash and never re-uploads the DLL. The dverse CLI talks raw Dataverse Web API (no Microsoft.PowerPlatform.Dataverse.Client dependency), reads the environment in a constant number of queries, canonicalizes both sides, and PATCHes only changed columns. Matching precedence for existing steps: explicit IdKey → natural key (plugin type, message, entity, stage) when unique on both sides → name; ambiguity is a hard error, never a heuristic.

Repository layout

src/Dverse.Cli/              the dverse CLI (net9.0, packs as dotnet tool Dverse.Cli)
src/Dverse.Sdk/              attributes (netstandard2.0) — the package plugins reference
src/Dverse.Sdk.Generators/   Roslyn incremental generators + diagnostics (ships inside Dverse.Sdk)
src/Dverse.Sdk.Targets/      MSBuild props/targets (ship inside Dverse.Sdk)
tests/                    unit, generator, and live-environment integration tests
samples/TestPlugins/      end-to-end sample plugin project (project references, for development)
samples/pcf/CreditGauge/  sample PCF control (scaffolded with `dverse pcf init`, built output committed)
demos/NugetDemo/          standalone consumer demo — uses only the published NuGet packages
docs/                     getting started, spkl migration, API spec, backlog

Building

dotnet build && dotnet test

Integration tests run only when DVERSE_TEST_URL is set and create only prefixed, torn-down test components. CI publishes prerelease packages to NuGet on every push to main.

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-ci.100 0 7/30/2026
0.1.0-ci.99 0 7/30/2026
0.1.0-ci.98 0 7/30/2026
0.1.0-ci.97 0 7/30/2026
0.1.0-ci.96 0 7/30/2026
0.1.0-ci.95 0 7/30/2026
0.1.0-ci.94 0 7/30/2026
0.1.0-ci.93 34 7/29/2026
0.1.0-ci.92 36 7/28/2026
0.1.0-ci.91 38 7/28/2026
0.1.0-ci.90 35 7/28/2026
0.1.0-ci.89 38 7/27/2026
0.1.0-ci.88 41 7/27/2026
0.1.0-ci.87 35 7/27/2026
0.1.0-ci.86 39 7/27/2026
0.1.0-ci.85 46 7/27/2026
0.1.0-ci.84 47 7/27/2026
0.1.0-ci.83 43 7/27/2026
0.1.0-ci.82 53 7/27/2026
0.1.0-ci.81 40 7/27/2026
Loading failed