Skip to main content

Migrating off IDirectLocalDispatcher

IDirectLocalDispatcher and both DispatchLocalAsync overloads have been removed from the public surface. If your build broke on either name, this page is the whole migration.

What to call instead​

IDispatcher.DispatchAsync. No cast, no opt-in, no configuration:

// Before
if (dispatcher is IDirectLocalDispatcher direct)
{
var response = await direct.DispatchLocalAsync<GetOrderQuery, OrderDto>(query, ct);
}

// After
var result = await dispatcher.DispatchAsync<GetOrderQuery, OrderDto>(query, ct);
var response = result.ReturnValue;

One behavioral difference to handle: DispatchAsync reports failure through the returned IMessageResult, where DispatchLocalAsync threw. A failure you previously caught is now a result you inspect -- see Results and Errors.

Why it was removed​

DispatchLocalAsync bypassed middleware unconditionally. Its eligibility check asked whether the handler invoker was the concrete one and whether local retries were off -- it never asked whether you had registered any middleware. So validation, authorization and telemetry that you had configured were silently skipped, with no diagnostic, on an injectable public API. Gating the method on middleware would only have made every call fall through to the standard path, so the method is gone instead.

Are you giving up performance?​

No -- you gain a little. The ultra-local fast path is an internal optimization, not an API, and it is unchanged: when a local action has no middleware applicable to its type, DispatchAsync takes the short path automatically, exactly as it did before. The explicit method was never the faster of the two. It measured slower than the standard call while doing strictly less work -- it created no message context and returned no IMessageResult -- so removing it makes the public call faster, not slower.

Tuning the fast path​

The fast path is still configurable through DispatchOptions.CrossCutting.Performance. It is used only when the message can stay local; otherwise Dispatch falls back to the full pipeline automatically. Common fallback triggers:

  • middleware applies to that message type
  • a non-local routing decision
  • a local retry mode that requires the richer execution path
  • operations that require full context-bound semantics

Context initialization on the fast path​

Context field/stateBehavior
context.MessageSet
context.CorrelationId (when correlation enabled and missing)Generated
context.CausationId (when missing and correlation present)Set from correlation
context.MessageType (when missing)Populated

Existing values are preserved -- Dispatch only fills missing values. Correlation is governed by Features.EnableCorrelation; when it is on, the fast path initializes it like any other path.

EmitDirectLocalResultMetadata​

  • false (default): minimal success result shape on the local fast path.
  • true: include full result metadata on local fast-path success.

See Core Configuration for the registration snippet and the appsettings.json equivalent.

See Also​