Multi-application workflows in the .NET SDK

Call activities, children, and detached workflows hosted in another Dapr application

Overview

Dapr workflows can call activities or child workflows that are hosted in a different Dapr application. In .NET, multi-application workflows are supported starting with:

  • Dapr runtime v1.16.0+
  • Dapr .NET SDK v1.17.0+

Conceptual guidance and constraints are covered in Multi Application Workflows.

Requirements

Multi-application workflow calls require:

  • The target app ID must exist and must register the activity or workflow you invoke.
  • All participating app IDs must be in the same namespace.
  • All participating app IDs must use the same workflow (actor) state store.

Call an activity in another application

Set TargetAppId on WorkflowTaskOptions when calling an activity to execute it in another app:

public sealed class BusinessWorkflow : Workflow<string, string>
{
    public override async Task<string> RunAsync(WorkflowContext context, string input)
    {
        var options = new WorkflowTaskOptions { TargetAppId = "App2" };
        var output = await context.CallActivityAsync<string>(nameof(ActivityA), input, options);
        return output;
    }
}

The parent workflow continues to orchestrate locally and receives the activity result.

Call a child workflow in another application

Set TargetAppId on ChildWorkflowTaskOptions when calling a child workflow to execute it in another app:

public sealed class BusinessWorkflow : Workflow<string, string>
{
    public override async Task<string> RunAsync(WorkflowContext context, string input)
    {
        var options = new ChildWorkflowTaskOptions { TargetAppId = "App2" };
        var output = await context.CallChildWorkflowAsync<string>(nameof(Workflow2), input, options);
        return output;
    }
}

Schedule a detached workflow in another application

SDK/runtime 1.19 also support independent, replay-safe detached workflow scheduling from the workflow context:

var detachedId = await context.ScheduleNewDetachedWorkflowAsync(
    workflowName: "DocumentWorkflow",
    instanceId: null,
    input: document,
    startTime: null,
    options: new WorkflowTaskOptions(TargetAppId: "document-service"));

Unlike CallChildWorkflowAsync, this returns the scheduled ID without waiting for output. The detached instance has independent failure and termination semantics: terminating the source workflow does not terminate it. The options overload allows TargetAppId and AllowPayloadReferences, but rejects RetryPolicy and any PropagationScope other than None.

Events and client targeting

WorkflowContext.SendEvent does not accept TargetAppId; it signals an instance in the current application. For external event submission, DaprWorkflowClient.RaiseEventAsync targets the application associated with the client’s sidecar, not an arbitrary app ID argument. Do not call a management client directly from deterministic workflow code to bypass that restriction; put external I/O in an activity.

Next steps