Skip to content

Cancel a pending RaiseAsync of an async external event #132

Closed

Description

@Nice3point

Description of the new feature / enhancement

A caller cancels a pending RaiseAsync, and Revit never runs the cancelled work.

The async external events take no CancellationToken.
A caller that stops waiting can't withdraw its work: Revit runs it later, and a change the user cancelled still changes the model.

  • RaiseAsync of IAsyncExternalEvent, IAsyncExternalEvent<T>, IAsyncRequestExternalEvent<TResult>, and IAsyncRequestExternalEvent<T, TResult> accepts a CancellationToken.
  • A token cancelled before the call raises nothing, and the task is cancelled at once.
  • A token cancelled before Revit runs the raise skips the handler for that raise, and the task is cancelled with that token.
  • A token cancelled while the handler runs changes nothing: the handler runs to its end, and the task completes with its result.
  • The other raises of the same event run as if the cancelled raise didn't exist.
  • A raise with ExternalEventOptions.AllowDirectInvocation in API mode checks the token once, before the handler runs.
  • The async event properties of the [ExternalEvent] generator and its extension methods for several arguments accept the token.

Scenario when this would be used?

  • A modeless window waits for an edit with a timeout while a modal dialog blocks Revit, and the edit stops once the timeout passes.
  • A service that stops at Revit shutdown cancels the work it raised.
  • A remote client cancels its request, and the add-in withdraws the Revit work of that request.

Priority

High (significant impact)

Activity

  1. self-assigned this
    on Oct 23, 2026
  2. Nice3point commented on Oct 23, 2026

    @Nice3point
    OwnerAuthor

    Decision

    • RaiseAsync of the four interfaces, the event classes, and the generated extension methods takes CancellationToken cancellationToken = default. Add-ins compiled against 2027.0 are rebuilt, and custom implementations of the interfaces add the parameter.
    • A handler can declare a CancellationToken as its last parameter, the way it declares UIApplication first. The asynchronous event passes it the token of RaiseAsync, and the synchronous event passes CancellationToken.None.
    • A running handler is never interrupted. A handler that receives the token can throw an OperationCanceledException for it, and the task is then canceled.
    • The handler sees a cancellation requested from another thread, such as a timeout or a remote client. A cancel button on the Revit thread takes effect only after the handler returns.
  3. Nice3point commented on Oct 23, 2026

    @Nice3point
    OwnerAuthor

    Correction

    The first line of the decision above no longer applies: the token is an overload, not an optional parameter.

    • RaiseAsync() stays, and RaiseAsync(CancellationToken) is declared next to it in the four interfaces, the event classes, and the generated extension methods.
    • Add-ins compiled against 2027.0 run unchanged. Custom implementations of the interfaces implement the overload.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions