diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs index abd313c05..a3f65de73 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/ActivityJsonConverter.cs @@ -49,7 +49,11 @@ public class ActivityJsonConverter( // If the activity type is not found, create a NotFoundActivity instead. if (activityDescriptor == null) { - var notFoundActivityDescriptor = activityRegistry.Find()!; + var notFoundActivityDescriptor = activityRegistry.Find(); + + if (notFoundActivityDescriptor == null) + throw new InvalidOperationException($"Unable to deserialize activity type '{activityTypeName}' because the NotFoundActivity descriptor is not registered. Ensure the activity registry has been populated before deserializing workflows."); + var notFoundActivityResult = JsonActivityConstructorContextHelper.CreateActivity(notFoundActivityDescriptor, activityRoot, clonedOptions); LogExceptionsIfAny(notFoundActivityResult); @@ -186,4 +190,4 @@ public class ActivityJsonConverter( clonedOptions.Converters.Add(new JsonIgnoreCompositeRootConverterFactory(serviceProvider.GetRequiredService())); return clonedOptions; } -} \ No newline at end of file +} diff --git a/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs b/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs index 5d088a57b..fd6c3d76c 100644 --- a/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs +++ b/test/unit/Elsa.Workflows.Core.UnitTests/Serialization/Converters/ActivityJsonConverterTests.cs @@ -48,11 +48,7 @@ public sealed class ActivityJsonConverterTests public void When_DeserializeUnknownActivity_Then_ReturnsNotFoundActivity() { // Arrange - var activityRegistry = Substitute.For(); - activityRegistry - .Find(NotFoundActivityTypeName) - .Returns(new ActivityDescriptor()); - + var activityRegistry = CreateUnknownActivityRegistry(new ActivityDescriptor()); var sut = CreateSut(activityRegistry); // Act @@ -92,6 +88,20 @@ public sealed class ActivityJsonConverterTests Assert.True(notFoundActivity.Metadata.ContainsKey("description")); } + [Fact] + public void When_DeserializeUnknownActivity_And_NotFoundActivityDescriptorMissing_Then_ThrowsClearException() + { + // Arrange + var activityRegistry = CreateUnknownActivityRegistry(); + var sut = CreateSut(activityRegistry); + + // Act + var exception = Assert.Throws(() => Execute(sut, UnknownActivityJson)); + + // Assert + Assert.Equal($"Unable to deserialize activity type '{UnknownActivityTypeName}' because the NotFoundActivity descriptor is not registered. Ensure the activity registry has been populated before deserializing workflows.", exception.Message); + } + [Fact] public void When_DeserializeWorkflowAsActivity_And_WorkflowDefinitionIdSpecified_Then_FindsAndInstantiatesActivity() { @@ -164,6 +174,13 @@ public sealed class ActivityJsonConverterTests return activityRegistry; } + static IActivityRegistry CreateUnknownActivityRegistry(ActivityDescriptor? notFoundActivityDescriptor = null) + { + var activityRegistry = Substitute.For(); + activityRegistry.Find(NotFoundActivityTypeName).Returns(notFoundActivityDescriptor); + return activityRegistry; + } + static IActivityRegistry CreateActivityRegistry_FindByCustomProperty(string customPropertyName, string customPropertyValue) { var descriptor = new ActivityDescriptor