dversedev

Reference

Context API

What a handler receives. None of this ships as a DLL — the generator emits it as internal source into your own assembly, which is why there is no runtime package to reference and nothing to ILMerge.

Reading a column is how it gets registered. ctx.PreImage.CreditLimit puts creditlimit on the pre-image and nothing else. When the analysis cannot prove the column set — you assigned the image to a variable, say — that is error DVERSE021 and you write an explicit [Image]. There is no silent fall back to all columns.

On RetrieveMultiple, restrict with ctx.Query.RestrictWith(…) — not Criteria.AddFilter. AddFilter attaches your filter as a child of the caller's root, so a caller who sends OR-rooted criteria (name eq A OR name eq B) turns your restriction into just another OR branch — and the query matches nearly everything. RestrictWith re-roots to And(callerCriteria, restriction) in place. Start with the ctx.IsAggregateQuery guard and return early: aggregate FetchXML is the one shape ctx.Query cannot normalise.

Contexts

IExecutionContext

interface

What every handler gets, whatever kind it is. Steps, custom APIs and jobs all extend this.

IOrganizationService Service The organization service as the calling user.
IOrganizationService SystemService The service as SYSTEM — bypasses the caller's privileges. Use deliberately.
IOrganizationService ServiceAs(Guid userId) The service impersonating a specific user.
Guid UserId The user the step executes as.
Guid InitiatingUserId The user who started the request — differs from UserId under impersonation.
Guid BusinessUnitId Business unit of the executing user.
int Depth Pipeline depth. 1 is a top-level call.
bool IsNested True when this execution was triggered by another plugin — the usual recursion guard.
Guid CorrelationId Correlates every step in one logical operation.
int UserLcid The user's language, for localized messages.
DateTime UtcNow The execution's timestamp. Injectable, so tests are not clock-dependent.
ISharedVariables Shared Typed shared variables, passed between steps in the same pipeline.
IEnvironmentVariables Env Environment variables, read by schema name.
IAsyncJobs Async Enqueue an async job transactionally.
IPluginHttp Http Outbound HTTP from the sandbox.
IManagedIdentityTokens ManagedIdentity Azure tokens via the assembly's managed identity — no stored credentials.
void Trace(string message, params object?[] args) Write to the plugin trace log, prefixed with the step key.
InvalidPluginExecutionException Fail(string message) Build the exception that aborts the operation. Throw the result.
InvalidPluginExecutionException Fail(string message, int errorCode) As above, with an error code.
InvalidPluginExecutionException FailLocalized(string resourceKey, params object?[] args) Fail with a message resolved from the [LocalizedStrings] catalog in the user's language.
IPluginExecutionContext Raw The platform context, for anything dverse does not wrap.
IServiceProvider Services The raw service provider.
ITracingService Tracing The raw tracing service.

IStepContext

interface : IExecutionContext

An untyped step handler's context — what a string-entity or global step receives.

Entity Target The Target input parameter.
EntityReference TargetRef A reference to the target row.
Entity PreImage The registered pre-image.
Entity PostImage The registered post-image.
string MessageName The message that fired, so one handler can serve Create and Update.
QueryExpression Query RetrieveMultiple only: the caller's query, normalized into one mutable QueryExpression whatever shape it arrived in.
bool IsAggregateQuery True for aggregate FetchXML, which cannot be normalized. Guard with this and return rather than fail.

IStepContext<TEntity>

interface : IStepContext

The typed step context — the one you normally write. Reading a column off PreImage or PostImage is what registers that column on the image.

TEntity Target The target, typed. Contains only the submitted columns.
TEntity PreImage The pre-image, typed. Each column you read is inferred into the registration.
TEntity PostImage The post-image, typed.
TEntity Projected Target overlaid on PreImage — the row as it will be after the write.
TEntity Current Target falling back to PreImage per column; on Create this is Target. Makes one handler natural across Create and Update.
bool IsSubmitted(string logicalName) Whether the caller actually submitted this column, as distinct from it being null.

IApiContext

interface : IExecutionContext

A global (unbound) custom API handler's context.

IApiContext<TEntity>

interface : IApiContext

A bound custom API handler's context — adds the entity the call was bound to.

EntityReference EntityRef Reference to the bound row.
Guid EntityId Id of the bound row.
TEntity Entity The bound row, fetched with the inferred column set (or the one [Fetch] declares).

IJobContext

interface : IExecutionContext

An async job body's context.

int Attempt 1-based attempt number, so a retry can behave differently.
string? Origin What enqueued the job.

Services on the context

ISharedVariables

interface

Typed access to the pipeline's shared variables. Keys carry their value type, so nothing is cast by hand.

void Set<T>(SharedKey<T> key, T value) Store a value for later steps.
bool TryGet<T>(SharedKey<T> key, out T? value) Read if present.
T GetRequired<T>(SharedKey<T> key) Read, or throw.

IEnvironmentVariables

interface

Environment variables by schema name. Values are captured into the snapshot at deploy time.

string Raw(string schemaName) The value, or throw when unset.
string? RawOrNull(string schemaName) The value, or null.
string Secret(string schemaName) A secret-type environment variable's value.

IAsyncJobs

interface

Transactional job enqueue: the job row is written in the same transaction as your data, so a rolled-back operation never leaves an orphaned job.

void Enqueue<TParams>(Action<IJobContext, TParams> job, TParams parameters, string? dedupeKey = null) Queue a [Job] method with its parameters. A dedupe key collapses duplicates.

IPluginHttp

interface

Outbound HTTP from inside the sandbox.

PluginHttpResponse GetJson(string url, string? bearer = null) GET returning JSON.
PluginHttpResponse PostJson(string url, string jsonBody, string? bearer = null) POST a JSON body.
PluginHttpResponse Send(PluginHttpRequest request) Full control over method, headers, body and timeout.

IManagedIdentityTokens

interface

Azure access tokens through the plugin assembly's managed identity — no client secret anywhere. Requires an Authenticode-signed assembly; see dverse sign init.

string AcquireTokenCached(string scope) Token for one scope, cached.
string AcquireTokenCached(IReadOnlyList<string> scopes) Token for several scopes.

PluginHttpRequest

class

A fully specified outbound request.

PluginHttpRequest(string method, string url) Construct with method and URL.
string Method HTTP method.
string Url Request URL.
string? Body Request body.
string? ContentType Content type.
Dictionary<string, string> Headers Request headers, case-insensitive.
TimeSpan Timeout Request timeout.default 30 seconds

PluginHttpResponse

class

The response.

bool IsSuccess True for 2xx.
int Status Status code.
string BodyText Response body as text.
T? Json<T>() Deserialize the body.

Optional<T>

readonly struct

A custom API request parameter the caller may omit — which is different from passing null. Response properties cannot be Optional (DVERSE028).

Skip

class

Suppress specific dverse steps for the writes a handler makes, so a plugin can update a row without re-triggering itself. Step ids resolve at compile time.

Skip.Self Skip the step currently executing.
Skip.Steps(...) Skip the named steps.

Queries

ITypedQuery<TEntity>

interface

Typed queries over a model class. The expression subset compiles to a QueryExpression — no Reflection.Emit, so it works in the sandbox.

ITypedQuery<TEntity> Where(Expression<Func<TEntity, bool>> predicate) Restrict.
ITypedQuery<TEntity> Select(Expression<Func<TEntity, object?>> projection) Choose columns.
ITypedQuery<TEntity> OrderBy(Expression<Func<TEntity, object?>> column) Sort ascending.
ITypedQuery<TEntity> OrderByDescending(Expression<Func<TEntity, object?>> column) Sort descending.
ITypedQuery<TEntity> Top(int count) Limit rows.
List<TEntity> ToList() Execute.
TEntity? FirstOrDefault() Execute, first row or null.

IQuery

interface

The untyped equivalent, for when the table is only known at runtime.

IQuery Select(params string[] columns) Choose columns.
IQuery SelectAll() All columns.
IQuery Where(string column, object? value) Equality restriction.
IQuery Where(string column, ConditionOperator @operator, params object?[] values) Any condition operator.
IQuery WhereIn(string column, IEnumerable values) IN restriction.
IQuery Link(string entity, string fromColumn, string toColumn, Action<ILink>? configure = null) Join another table.
IQuery OrderBy(string column) Sort ascending.
IQuery OrderByDescending(string column) Sort descending.
IQuery Top(int count) Limit rows.
List<Entity> ToList() Execute.
Entity? FirstOrDefault() Execute, first row or null.
bool Any() Whether any row matches.
QueryExpression Build() The underlying QueryExpression, unexecuted.

Testing

TestStepContext / TestStepContext<TEntity>

class

A step context double. Set Target, PreImage and PostImage, run the handler, assert — no environment, no mocking framework. Ships inside your own plugin assembly, so tests reference the assembly, not a package.

InMemoryOrganizationService

class

An IOrganizationService backed by an in-memory row store, supporting create, retrieve, update, delete, queries with link joins and aliased columns, and the file block protocol.