Support built in CallHttpAsync in Standalone SDK
Summary
Add built-in BuiltIn::HttpActivity support to the standalone worker SDK (Microsoft.DurableTask.Worker) so that CallHttpAsync works when using durabletask-dotnet to connect to sidecar (e.g.,, azuremanaged backend).
Today, CallHttpAsync only works when the Azure Functions Durable Task extension host is present, because the host intercepts the BuiltIn::HttpActivity task in TaskHttpActivityShim before it reaches the worker. In standalone mode, the activity dispatches to the worker, which has no registration for it and fails with a non-retriable ActivityTaskNotFound error.
Motivation
The standalone SDK (Microsoft.DurableTask.Client + Microsoft.DurableTask.Worker) is increasingly used outside Azure Functions — with , Dapr Workflow, and dts backend. HTTP calls are one of the most common orchestration primitives. Requiring users to hand-roll their own HTTP activity to achieve what CallHttpAsync provides out of the box in Azure Functions creates an unnecessary capability gap.
Current behavior (standalone + dts backend)
// This compiles only if you reference Worker.Extensions.DurableTask (Azure Functions package)
// and fails at runtime because nobody handles the built-in activity:
var response = await context.CallHttpAsync(new DurableHttpRequest(HttpMethod.Get, new Uri("https://example.com")));
// → TaskFailedException: ActivityTaskNotFound — "No activity task named 'BuiltIn::HttpActivity' was found."
Even calling it manually without the extension method produces the same failure:
await context.CallActivityAsync<DurableHttpResponse>("BuiltIn::HttpActivity", request);
// → same ActivityTaskNotFound error
Expected behavior
CallHttpAsync (or an equivalent API) should work out of the box with any backend, not just Azure Functions.
Proposed Design
Auto-register a built-in HTTP activity implementation inside DurableTaskWorker that executes the HTTP call locally using HttpClient. This mirrors the approach used by TaskHttpActivityShim in the Functions host, but lives in the SDK itself.
Key changes
-
New internal class BuiltInHttpActivity in Microsoft.DurableTask.Worker — implements ITaskActivity, uses HttpClient to execute the DurableHttpRequest and return a DurableHttpResponse.
-
Auto-registration in DurableTaskWorkerBuilder.Build() — inject BuiltInHttpActivity for the name "BuiltIn::HttpActivity" unless the user has explicitly registered their own activity with that name.
-
Move CallHttpAsync extension method and HTTP types to the core SDK — the CallHttpAsync extension method, DurableHttpRequest, and DurableHttpResponse currently live in the Azure Functions extension package. They should be available to standalone SDK users without requiring a dependency on Worker.Extensions.DurableTask.
-
User override — if a user registers their own "BuiltIn::HttpActivity" factory, the auto-registration yields to the user's implementation.
What to support in v1
| Feature |
Support |
Notes |
| HTTP methods (GET/POST/PUT/DELETE/PATCH) |
Yes |
Core functionality |
| Custom headers |
Yes |
Passed through to HttpRequestMessage |
| Request body |
Yes |
String content |
| Response status + headers + body |
Yes |
Mapped to DurableHttpResponse |
| Timeout |
Yes |
From DurableHttpRequest.Timeout |
AsynchronousPatternEnabled (202 polling) |
No (v2) |
Complex loop — return 202 as-is with a log warning |
TokenSource / Managed Identity |
No (v2) |
Requires Azure.Identity dependency |
HttpRetryOptions |
No (v2) |
Durable Task already supports retries via TaskOptions at the activity level |
Architecture
Orchestrator → CallHttpAsync(request)
→ CallActivityAsync("BuiltIn::HttpActivity", request)
→ sidecar dispatches to worker
→ DurableTaskWorker activity lookup
→ BuiltInHttpActivity.RunAsync()
→ HttpClient.SendAsync(...)
→ return DurableHttpResponse
This is the same flow as any user-defined activity, except the SDK pre-registers it.
Alternatives Considered
-
Document "just write your own HTTP activity" — shifts burden to every standalone user. Boilerplate for a universal primitive.
-
Move it to a separate NuGet package (Microsoft.DurableTask.Worker.Http) — possible but adds packaging overhead for a feature that should be first-class.
Additional Context
- The Java SDK (
durabletask-java) has the same gap — DurableHttp.callHttp() schedules BuiltIn::HttpActivity but the standalone worker has no handler. A parallel enhancement is being proposed there.
- The Python SDK (
durabletask-python) would benefit from the same pattern.
Support built in
CallHttpAsyncin Standalone SDKSummary
Add built-in
BuiltIn::HttpActivitysupport to the standalone worker SDK (Microsoft.DurableTask.Worker) so thatCallHttpAsyncworks when usingdurabletask-dotnetto connect to sidecar (e.g.,, azuremanaged backend).Today,
CallHttpAsynconly works when the Azure Functions Durable Task extension host is present, because the host intercepts theBuiltIn::HttpActivitytask inTaskHttpActivityShimbefore it reaches the worker. In standalone mode, the activity dispatches to the worker, which has no registration for it and fails with a non-retriableActivityTaskNotFounderror.Motivation
The standalone SDK (
Microsoft.DurableTask.Client+Microsoft.DurableTask.Worker) is increasingly used outside Azure Functions — with , Dapr Workflow, and dts backend. HTTP calls are one of the most common orchestration primitives. Requiring users to hand-roll their own HTTP activity to achieve whatCallHttpAsyncprovides out of the box in Azure Functions creates an unnecessary capability gap.Current behavior (standalone + dts backend)
Even calling it manually without the extension method produces the same failure:
Expected behavior
CallHttpAsync(or an equivalent API) should work out of the box with any backend, not just Azure Functions.Proposed Design
Auto-register a built-in HTTP activity implementation inside
DurableTaskWorkerthat executes the HTTP call locally usingHttpClient. This mirrors the approach used byTaskHttpActivityShimin the Functions host, but lives in the SDK itself.Key changes
New internal class
BuiltInHttpActivityinMicrosoft.DurableTask.Worker— implementsITaskActivity, usesHttpClientto execute theDurableHttpRequestand return aDurableHttpResponse.Auto-registration in
DurableTaskWorkerBuilder.Build()— injectBuiltInHttpActivityfor the name"BuiltIn::HttpActivity"unless the user has explicitly registered their own activity with that name.Move
CallHttpAsyncextension method and HTTP types to the core SDK — theCallHttpAsyncextension method,DurableHttpRequest, andDurableHttpResponsecurrently live in the Azure Functions extension package. They should be available to standalone SDK users without requiring a dependency onWorker.Extensions.DurableTask.User override — if a user registers their own
"BuiltIn::HttpActivity"factory, the auto-registration yields to the user's implementation.What to support in v1
HttpRequestMessageDurableHttpResponseDurableHttpRequest.TimeoutAsynchronousPatternEnabled(202 polling)TokenSource/ Managed IdentityAzure.IdentitydependencyHttpRetryOptionsTaskOptionsat the activity levelArchitecture
This is the same flow as any user-defined activity, except the SDK pre-registers it.
Alternatives Considered
Document "just write your own HTTP activity" — shifts burden to every standalone user. Boilerplate for a universal primitive.
Move it to a separate NuGet package (
Microsoft.DurableTask.Worker.Http) — possible but adds packaging overhead for a feature that should be first-class.Additional Context
durabletask-java) has the same gap —DurableHttp.callHttp()schedulesBuiltIn::HttpActivitybut the standalone worker has no handler. A parallel enhancement is being proposed there.durabletask-python) would benefit from the same pattern.