@@ -335,6 +335,71 @@ await this.worker
335335 }
336336 }
337337
338+ [ TestMethod ]
339+ // Test that when a provider is set, properties of exception thrown by orchestration directly will be included
340+ // if excception type is matched.
341+ public async Task ExceptionPropertiesProvider_SimpleThrowExceptionOrchestration ( )
342+ {
343+ this . worker . ExceptionPropertiesProvider = new TestExceptionPropertiesProvider ( ) ;
344+ this . worker . ErrorPropagationMode = ErrorPropagationMode . UseFailureDetails ;
345+
346+ try
347+ {
348+ await this . worker
349+ . AddTaskOrchestrations ( typeof ( SimpleThrowExceptionOrchestration ) )
350+ . StartAsync ( ) ;
351+
352+ var instance = await this . client . CreateOrchestrationInstanceAsync ( typeof ( SimpleThrowExceptionOrchestration ) , "test-input" ) ;
353+ var result = await this . client . WaitForOrchestrationAsync ( instance , DefaultTimeout ) ;
354+
355+ // Check that custom properties were extracted
356+ Assert . AreEqual ( OrchestrationStatus . Failed , result . OrchestrationStatus ) ;
357+ Assert . IsNotNull ( result . FailureDetails ) ;
358+ Assert . IsNotNull ( result . FailureDetails . Properties ) ;
359+
360+ // Check the properties match the ArgumentOutOfRangeException.
361+ Assert . AreEqual ( "count" , result . FailureDetails . Properties [ "Name" ] ) ;
362+ Assert . AreEqual ( "100" , result . FailureDetails . Properties [ "Value" ] ) ;
363+ }
364+ finally
365+ {
366+ await this . worker . StopAsync ( ) ;
367+ }
368+ }
369+
370+ [ TestMethod ]
371+ // Test that when a provider is set, exception properties are included in failure details with propogation.
372+ public async Task ExceptionPropertiesProvider_SubOrchestrationThrowExceptionOrchestration ( )
373+ {
374+ this . worker . ExceptionPropertiesProvider = new TestExceptionPropertiesProvider ( ) ;
375+ this . worker . ErrorPropagationMode = ErrorPropagationMode . UseFailureDetails ;
376+
377+ try
378+ {
379+ await this . worker
380+ . AddTaskOrchestrations ( typeof ( SubOrchestrationThrowExceptionOrchestration ) )
381+ . AddTaskOrchestrations ( typeof ( ThrowArgumentOutofRangeExceptionASubOrchestration ) )
382+ . AddTaskActivities ( typeof ( ThrowArgumentOutofRangeExceptionActivity ) )
383+ . StartAsync ( ) ;
384+
385+ var instance = await this . client . CreateOrchestrationInstanceAsync ( typeof ( SubOrchestrationThrowExceptionOrchestration ) , "test-input" ) ;
386+ var result = await this . client . WaitForOrchestrationAsync ( instance , DefaultTimeout ) ;
387+
388+ // Check that custom properties were extracted
389+ Assert . AreEqual ( OrchestrationStatus . Failed , result . OrchestrationStatus ) ;
390+ Assert . IsNotNull ( result . FailureDetails ) ;
391+ Assert . IsNotNull ( result . FailureDetails . Properties ) ;
392+
393+ // Check the properties match the ArgumentOutOfRangeException.
394+ Assert . AreEqual ( "count" , result . FailureDetails . Properties [ "Name" ] ) ;
395+ Assert . AreEqual ( "100" , result . FailureDetails . Properties [ "Value" ] ) ;
396+ }
397+ finally
398+ {
399+ await this . worker . StopAsync ( ) ;
400+ }
401+ }
402+
338403 class ThrowCustomExceptionOrchestration : TaskOrchestration < string , string >
339404 {
340405 public override async Task < string > RunTask ( OrchestrationContext context , string input )
@@ -352,6 +417,40 @@ protected override string Execute(TaskContext context, string input)
352417 }
353418 }
354419
420+ class SimpleThrowExceptionOrchestration : TaskOrchestration < string , string >
421+ {
422+ public override Task < string > RunTask ( OrchestrationContext context , string input )
423+ {
424+ throw new ArgumentOutOfRangeException ( "count" , 100 , "Count is not valid." ) ;
425+ }
426+ }
427+
428+ class SubOrchestrationThrowExceptionOrchestration : TaskOrchestration < string , string >
429+ {
430+ public override async Task < string > RunTask ( OrchestrationContext context , string input )
431+ {
432+ await context . CreateSubOrchestrationInstance < string > ( typeof ( ThrowArgumentOutofRangeExceptionASubOrchestration ) , input ) ;
433+ return "This should never be reached" ;
434+ }
435+ }
436+
437+ class ThrowArgumentOutofRangeExceptionASubOrchestration : TaskOrchestration < string , string >
438+ {
439+ public override async Task < string > RunTask ( OrchestrationContext context , string input )
440+ {
441+ await context . ScheduleTask < string > ( typeof ( ThrowArgumentOutofRangeExceptionActivity ) , input ) ;
442+ return "This should never be reached" ;
443+ }
444+ }
445+
446+ class ThrowArgumentOutofRangeExceptionActivity : TaskActivity < string , string >
447+ {
448+ protected override string Execute ( TaskContext context , string input )
449+ {
450+ throw new ArgumentOutOfRangeException ( "count" , 100 , "Count is not valid." ) ;
451+ }
452+ }
453+
355454 class ThrowInvalidOperationExceptionOrchestration : TaskOrchestration < string , string >
356455 {
357456 public override async Task < string > RunTask ( OrchestrationContext context , string input )
@@ -409,6 +508,11 @@ class TestExceptionPropertiesProvider : IExceptionPropertiesProvider
409508 {
410509 return exception switch
411510 {
511+ ArgumentOutOfRangeException e => new Dictionary < string , object ? >
512+ {
513+ [ "Name" ] = e . ParamName ?? string . Empty ,
514+ [ "Value" ] = e . ActualValue ? . ToString ( ) ?? string . Empty ,
515+ } ,
412516 CustomBusinessException businessEx => new Dictionary < string , object ? >
413517 {
414518 [ "ExceptionTypeName" ] = nameof ( CustomBusinessException ) ,
0 commit comments