diff --git a/samples/durable-functions/dotnet/CustomExceptionPropertyProvider/CustomExceptionPropertyProvider.csproj b/samples/durable-functions/dotnet/CustomExceptionPropertyProvider/CustomExceptionPropertyProvider.csproj
new file mode 100644
index 00000000..1d2aad47
--- /dev/null
+++ b/samples/durable-functions/dotnet/CustomExceptionPropertyProvider/CustomExceptionPropertyProvider.csproj
@@ -0,0 +1,21 @@
+
+
+ net8.0
+ v4
+ Exe
+ enable
+ enable
+ CustomExceptionPropertyProvider
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/durable-functions/dotnet/CustomExceptionPropertyProvider/Functions.cs b/samples/durable-functions/dotnet/CustomExceptionPropertyProvider/Functions.cs
new file mode 100644
index 00000000..bcdd69da
--- /dev/null
+++ b/samples/durable-functions/dotnet/CustomExceptionPropertyProvider/Functions.cs
@@ -0,0 +1,140 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Microsoft.Azure.Functions.Worker;
+using Microsoft.Azure.Functions.Worker.Http;
+using Microsoft.DurableTask;
+using Microsoft.DurableTask.Client;
+using Microsoft.DurableTask.Worker;
+
+namespace CustomExceptionPropertyProvider;
+
+// =============================================================================
+// Orchestration + activity
+// =============================================================================
+
+///
+/// Demonstrates custom FailureDetails properties. An activity throws a
+/// ; the registered
+/// attaches its structured fields to
+/// the failure. The orchestration catches the propagated
+/// and returns its FailureDetails,
+/// including the custom Properties.
+///
+public static class CustomExceptionOrchestration
+{
+ [Function(nameof(OrchestrationWithCustomException))]
+ public static async Task OrchestrationWithCustomException(
+ [OrchestrationTrigger] TaskOrchestrationContext context)
+ {
+ try
+ {
+#pragma warning disable DURABLE2001 // Activity has no input
+ await context.CallActivityAsync(nameof(BusinessActivity));
+#pragma warning restore DURABLE2001
+ }
+ catch (TaskFailedException ex)
+ {
+ // FailureDetails.Properties contains the values supplied by the provider.
+ return ex.FailureDetails;
+ }
+
+ // Should never reach here — the activity always throws.
+ return null;
+ }
+
+ [Function(nameof(BusinessActivity))]
+ public static void BusinessActivity([ActivityTrigger] TaskActivityContext context)
+ {
+ throw new BusinessValidationException(
+ message: "Business logic validation failed",
+ stringProperty: "validation-error-123",
+ intProperty: 100,
+ longProperty: 999999999L,
+ dateTimeProperty: new DateTime(2025, 10, 15, 14, 30, 0, DateTimeKind.Utc),
+ dictionaryProperty: new Dictionary
+ {
+ ["error_code"] = "VALIDATION_FAILED",
+ ["retry_count"] = 3,
+ ["is_critical"] = true,
+ },
+ listProperty: new List