diff --git a/Directory.Packages.props b/Directory.Packages.props
index 8388030fa..7a24d9b7f 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -23,6 +23,7 @@
+
@@ -33,6 +34,11 @@
+
+
+
+
+
diff --git a/Microsoft.DurableTask.sln b/Microsoft.DurableTask.sln
index 26c2e80de..383f2e158 100644
--- a/Microsoft.DurableTask.sln
+++ b/Microsoft.DurableTask.sln
@@ -93,6 +93,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScheduleWebApp", "samples\S
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScheduledTasks.Tests", "test\ScheduledTasks.Tests\ScheduledTasks.Tests.csproj", "{D2779F32-A548-44F8-B60A-6AC018966C79}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LargePayloadConsoleApp", "samples\LargePayloadConsoleApp\LargePayloadConsoleApp.csproj", "{6EB9D002-62C8-D6C1-62A8-14C54CA6DBBC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureBlobPayloads", "src\Extensions\AzureBlobPayloads\AzureBlobPayloads.csproj", "{FE1DA748-D6DB-E168-BC42-6DBBCEAF229C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -247,6 +251,14 @@ Global
{D2779F32-A548-44F8-B60A-6AC018966C79}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2779F32-A548-44F8-B60A-6AC018966C79}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2779F32-A548-44F8-B60A-6AC018966C79}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6EB9D002-62C8-D6C1-62A8-14C54CA6DBBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6EB9D002-62C8-D6C1-62A8-14C54CA6DBBC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6EB9D002-62C8-D6C1-62A8-14C54CA6DBBC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6EB9D002-62C8-D6C1-62A8-14C54CA6DBBC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FE1DA748-D6DB-E168-BC42-6DBBCEAF229C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FE1DA748-D6DB-E168-BC42-6DBBCEAF229C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FE1DA748-D6DB-E168-BC42-6DBBCEAF229C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FE1DA748-D6DB-E168-BC42-6DBBCEAF229C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -293,6 +305,8 @@ Global
{A89B766C-987F-4C9F-8937-D0AB9FE640C8} = {EFF7632B-821E-4CFC-B4A0-ED4B24296B17}
{100348B5-4D97-4A3F-B777-AB14F276F8FE} = {EFF7632B-821E-4CFC-B4A0-ED4B24296B17}
{D2779F32-A548-44F8-B60A-6AC018966C79} = {E5637F81-2FB9-4CD7-900D-455363B142A7}
+ {6EB9D002-62C8-D6C1-62A8-14C54CA6DBBC} = {EFF7632B-821E-4CFC-B4A0-ED4B24296B17}
+ {FE1DA748-D6DB-E168-BC42-6DBBCEAF229C} = {8AFC9781-F6F1-4696-BB4A-9ED7CA9D612B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AB41CB55-35EA-4986-A522-387AB3402E71}
diff --git a/samples/LargePayloadConsoleApp/LargePayloadConsoleApp.csproj b/samples/LargePayloadConsoleApp/LargePayloadConsoleApp.csproj
new file mode 100644
index 000000000..b0f2914c7
--- /dev/null
+++ b/samples/LargePayloadConsoleApp/LargePayloadConsoleApp.csproj
@@ -0,0 +1,24 @@
+
+
+
+ Exe
+ net8.0
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/LargePayloadConsoleApp/Program.cs b/samples/LargePayloadConsoleApp/Program.cs
new file mode 100644
index 000000000..87258e1ea
--- /dev/null
+++ b/samples/LargePayloadConsoleApp/Program.cs
@@ -0,0 +1,204 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using Microsoft.DurableTask.Client;
+using Microsoft.DurableTask.Client.AzureManaged;
+using Microsoft.DurableTask.Client.Entities;
+using Microsoft.DurableTask.Entities;
+using Microsoft.DurableTask.Worker;
+using Microsoft.DurableTask.Worker.AzureManaged;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+// Demonstrates Large Payload Externalization using Azure Blob Storage.
+// This sample uses Azurite/emulator by default via UseDevelopmentStorage=true.
+
+HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
+
+// Connection string for Durable Task Scheduler
+string schedulerConnectionString = builder.Configuration.GetValue("DURABLE_TASK_SCHEDULER_CONNECTION_STRING")
+ ?? throw new InvalidOperationException("Missing required configuration 'DURABLE_TASK_SCHEDULER_CONNECTION_STRING'");
+
+// Configure Durable Task client with Durable Task Scheduler and externalized payloads
+builder.Services.AddDurableTaskClient(b =>
+{
+ b.UseDurableTaskScheduler(schedulerConnectionString);
+ // Ensure entity APIs are enabled for the client
+ b.Configure(o => { o.EnableEntitySupport = true; o.EnableLargePayloadSupport = true; });
+ b.UseExternalizedPayloads(opts =>
+ {
+ // Keep threshold small to force externalization for demo purposes
+ opts.ExternalizeThresholdBytes = 1024; // 1KB
+ opts.ConnectionString = builder.Configuration.GetValue("DURABLETASK_STORAGE") ?? "UseDevelopmentStorage=true";
+ opts.ContainerName = builder.Configuration.GetValue("DURABLETASK_PAYLOAD_CONTAINER");
+ });
+});
+
+// Configure Durable Task worker with tasks and externalized payloads
+builder.Services.AddDurableTaskWorker(b =>
+{
+ b.UseDurableTaskScheduler(schedulerConnectionString);
+ b.AddTasks(tasks =>
+ {
+ // Orchestrator: call activity first, return its output (should equal original input)
+ tasks.AddOrchestratorFunc("LargeInputEcho", async (ctx, input) =>
+ {
+ string echoed = await ctx.CallActivityAsync("Echo", input);
+ return echoed;
+ });
+
+ // Activity: validate it receives raw input (not token) and return it
+ tasks.AddActivityFunc("Echo", (ctx, value) =>
+ {
+ if (value is null)
+ {
+ return string.Empty;
+ }
+
+ // If we ever see a token in the activity, externalization is not being resolved correctly.
+ if (value.StartsWith("blob:v1:", StringComparison.Ordinal))
+ {
+ throw new InvalidOperationException("Activity received a payload token instead of raw input.");
+ }
+
+ return value;
+ });
+
+ // Entity samples
+ // 1) Large entity operation input (worker externalizes input; entity receives resolved payload)
+ tasks.AddOrchestratorFunc