From 6b119e4540ab40b5fe66d832423710a34bf9744e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Milewski?= Date: Wed, 11 Sep 2024 08:40:43 +0200 Subject: [PATCH] 0.13.x fixes - overwrite on IExecutionContext registering - exception on not found embedded activity - definition and runtime exceptions --- .../Activities/Classes/ActivityId.cs | 2 +- Core/Stateflows.Common/DependencyInjection.cs | 2 +- Core/Stateflows.Common/Events/Request.cs | 2 +- .../Exceptions/BehaviorDefinitionException.cs | 21 ++++ .../Exceptions/BehaviorInstanceException.cs | 2 +- ...ception.cs => BehaviorRuntimeException.cs} | 6 +- .../Exceptions/ExecutionException.cs | 2 +- .../Exceptions/SerializationException.cs | 2 +- .../StateflowsDefinitionException.cs | 12 ++ .../Exceptions/StateflowsRuntimeException.cs | 12 ++ .../Exceptions/TransportException.cs | 2 +- .../StateMachines/Classes/StateMachineId.cs | 2 +- .../Sequence/ExecutionSequence.cs | 2 +- .../ActivitiesDependencyInjection.cs | 15 +-- ...xtHolder.cs => ActivitiesContextHolder.cs} | 5 +- Core/Stateflows/Activities/Engine/Executor.cs | 2 +- .../Stateflows/Activities/Engine/NodeScope.cs | 100 ++++++++-------- .../Exceptions/ActivityDefinitionException.cs | 2 +- .../Exceptions/ActivityException.cs | 2 +- Core/Stateflows/Activities/Models/Graph.cs | 3 + .../Registration/Builders/ActivityBuilder.cs | 2 +- .../Builders/BaseActivityBuilder.cs | 6 +- .../Registration/Builders/FlowBuilder.cs | 4 +- .../CompositeStateBuilderExtensions.cs | 56 ++------- .../DefaultTransitionBuilderExtensions.cs | 73 +----------- .../InternalTransitionBuilderExtensions.cs | 72 +----------- .../Extensions/StateBuilderExtensions.cs | 59 ++-------- .../StateMachineActivityExtensions.cs | 110 ++++++++++++++++++ .../Extensions/TransitionBuilderExtensions.cs | 74 +----------- .../Common/Classes/BaseValueAccessor.cs | 2 +- .../Common/Context/CommonContextHolder.cs | 9 ++ Core/Stateflows/DependencyInjection.cs | 5 + ...older.cs => StateMachinesContextHolder.cs} | 5 +- .../StateMachines/Engine/Executor.cs | 48 ++++---- .../StateMachines/Engine/Plugins/Behaviors.cs | 5 + .../StateMachineDefinitionException.cs | 19 ++- .../Exceptions/StateMachineException.cs | 22 ---- .../StateMachineRuntimeException.cs | 11 ++ .../StateMachines/Helpers/StateAction.cs | 2 + Core/Stateflows/StateMachines/Models/Graph.cs | 11 ++ .../Registration/Builders/StateBuilder.cs | 15 ++- .../Builders/StateMachineBuilder.cs | 3 +- .../Builders/TransitionBuilder.cs | 4 +- .../Registration/StateMachinesRegister.cs | 12 +- .../StateMachinesDependencyInjection.cs | 13 +-- .../DependencyInjection.cs | 2 +- .../DependencyInjection.cs | 2 +- .../DependencyInjection.cs | 2 +- .../Tests/Typed.cs | 4 +- 49 files changed, 385 insertions(+), 465 deletions(-) create mode 100644 Core/Stateflows.Common/Exceptions/BehaviorDefinitionException.cs rename Core/Stateflows.Common/Exceptions/{BehaviorException.cs => BehaviorRuntimeException.cs} (56%) create mode 100644 Core/Stateflows.Common/Exceptions/StateflowsDefinitionException.cs create mode 100644 Core/Stateflows.Common/Exceptions/StateflowsRuntimeException.cs rename Core/Stateflows/Activities/Context/{ContextHolder.cs => ActivitiesContextHolder.cs} (74%) create mode 100644 Core/Stateflows/Activities/StateMachines/Extensions/StateMachineActivityExtensions.cs create mode 100644 Core/Stateflows/Common/Context/CommonContextHolder.cs rename Core/Stateflows/StateMachines/Context/{ContextHolder.cs => StateMachinesContextHolder.cs} (70%) delete mode 100644 Core/Stateflows/StateMachines/Exceptions/StateMachineException.cs create mode 100644 Core/Stateflows/StateMachines/Exceptions/StateMachineRuntimeException.cs diff --git a/Core/Stateflows.Common/Activities/Classes/ActivityId.cs b/Core/Stateflows.Common/Activities/Classes/ActivityId.cs index 0e2bfc08..301729c8 100644 --- a/Core/Stateflows.Common/Activities/Classes/ActivityId.cs +++ b/Core/Stateflows.Common/Activities/Classes/ActivityId.cs @@ -17,7 +17,7 @@ public ActivityId(BehaviorId id) { if (id.Type != BehaviorType.Activity) { - throw new StateflowsException("BehaviorId doesn't represent Activity"); + throw new StateflowsDefinitionException("BehaviorId doesn't represent Activity"); } Name = id.Name; diff --git a/Core/Stateflows.Common/DependencyInjection.cs b/Core/Stateflows.Common/DependencyInjection.cs index d8e8bfd6..60d5b868 100644 --- a/Core/Stateflows.Common/DependencyInjection.cs +++ b/Core/Stateflows.Common/DependencyInjection.cs @@ -21,7 +21,7 @@ public static IServiceCollection AddStateflowsClient(this IServiceCollection ser { buildAction.ThrowIfNull(nameof(buildAction)); - if (services.IsServiceRegistered()) throw new StateflowsException("Stateflows client already registered"); + if (services.IsServiceRegistered()) throw new StateflowsDefinitionException("Stateflows client already registered"); var builder = new StateflowsClientBuilder(services); diff --git a/Core/Stateflows.Common/Events/Request.cs b/Core/Stateflows.Common/Events/Request.cs index 964f49fc..6fab0b23 100644 --- a/Core/Stateflows.Common/Events/Request.cs +++ b/Core/Stateflows.Common/Events/Request.cs @@ -9,7 +9,7 @@ public void Respond(TResponse response) { if (Response != null) { - throw new StateflowsException($"Already responded to request '{Name}'"); + throw new StateflowsRuntimeException($"Already responded to request '{Name}'"); } Response = response; diff --git a/Core/Stateflows.Common/Exceptions/BehaviorDefinitionException.cs b/Core/Stateflows.Common/Exceptions/BehaviorDefinitionException.cs new file mode 100644 index 00000000..3b868084 --- /dev/null +++ b/Core/Stateflows.Common/Exceptions/BehaviorDefinitionException.cs @@ -0,0 +1,21 @@ +using System; + +namespace Stateflows.Common.Exceptions +{ +#pragma warning disable S3925 // "ISerializable" should be implemented correctly + public class BehaviorDefinitionException : StateflowsDefinitionException + { + public BehaviorClass BehaviorClass { get; } + + public BehaviorDefinitionException(string message, BehaviorClass behaviorClass) : base(message) + { + BehaviorClass = behaviorClass; + } + + public BehaviorDefinitionException(string message, BehaviorClass behaviorClass, Exception innerException) : base(message, innerException) + { + BehaviorClass = behaviorClass; + } + } +#pragma warning restore S3925 // "ISerializable" should be implemented correctly +} diff --git a/Core/Stateflows.Common/Exceptions/BehaviorInstanceException.cs b/Core/Stateflows.Common/Exceptions/BehaviorInstanceException.cs index 55b1d9dc..b0780cc5 100644 --- a/Core/Stateflows.Common/Exceptions/BehaviorInstanceException.cs +++ b/Core/Stateflows.Common/Exceptions/BehaviorInstanceException.cs @@ -3,7 +3,7 @@ namespace Stateflows.Common.Exceptions { #pragma warning disable S3925 // "ISerializable" should be implemented correctly - public class BehaviorInstanceException : BehaviorException + public class BehaviorInstanceException : BehaviorRuntimeException { public BehaviorId BehaviorId { get; } diff --git a/Core/Stateflows.Common/Exceptions/BehaviorException.cs b/Core/Stateflows.Common/Exceptions/BehaviorRuntimeException.cs similarity index 56% rename from Core/Stateflows.Common/Exceptions/BehaviorException.cs rename to Core/Stateflows.Common/Exceptions/BehaviorRuntimeException.cs index 5523a49d..0b1393e1 100644 --- a/Core/Stateflows.Common/Exceptions/BehaviorException.cs +++ b/Core/Stateflows.Common/Exceptions/BehaviorRuntimeException.cs @@ -3,16 +3,16 @@ namespace Stateflows.Common.Exceptions { #pragma warning disable S3925 // "ISerializable" should be implemented correctly - public class BehaviorException : StateflowsException + public class BehaviorRuntimeException : StateflowsRuntimeException { public BehaviorClass BehaviorClass { get; } - public BehaviorException(string message, BehaviorClass behaviorClass) : base(message) + public BehaviorRuntimeException(string message, BehaviorClass behaviorClass) : base(message) { BehaviorClass = behaviorClass; } - public BehaviorException(string message, BehaviorClass behaviorClass, Exception innerException) : base(message, innerException) + public BehaviorRuntimeException(string message, BehaviorClass behaviorClass, Exception innerException) : base(message, innerException) { BehaviorClass = behaviorClass; } diff --git a/Core/Stateflows.Common/Exceptions/ExecutionException.cs b/Core/Stateflows.Common/Exceptions/ExecutionException.cs index e9feeef2..f579b35d 100644 --- a/Core/Stateflows.Common/Exceptions/ExecutionException.cs +++ b/Core/Stateflows.Common/Exceptions/ExecutionException.cs @@ -3,7 +3,7 @@ namespace Stateflows.Common.Exceptions { #pragma warning disable S3925 // "ISerializable" should be implemented correctly - public class ExecutionException : StateflowsException + public class ExecutionException : StateflowsDefinitionException { public ExecutionException(Exception innerException) : base(string.Empty, innerException) { } } diff --git a/Core/Stateflows.Common/Exceptions/SerializationException.cs b/Core/Stateflows.Common/Exceptions/SerializationException.cs index 0a1be149..c8b28034 100644 --- a/Core/Stateflows.Common/Exceptions/SerializationException.cs +++ b/Core/Stateflows.Common/Exceptions/SerializationException.cs @@ -3,7 +3,7 @@ namespace Stateflows.Common.Exceptions { #pragma warning disable S3925 // "ISerializable" should be implemented correctly - public class SerializationException : StateflowsException + public class SerializationException : StateflowsDefinitionException { public SerializationException(string message) : base(message) { } public SerializationException(string message, Exception innerException) : base(message, innerException) { } diff --git a/Core/Stateflows.Common/Exceptions/StateflowsDefinitionException.cs b/Core/Stateflows.Common/Exceptions/StateflowsDefinitionException.cs new file mode 100644 index 00000000..aa8d0885 --- /dev/null +++ b/Core/Stateflows.Common/Exceptions/StateflowsDefinitionException.cs @@ -0,0 +1,12 @@ +using System; + +namespace Stateflows.Common.Exceptions +{ +#pragma warning disable S3925 // "ISerializable" should be implemented correctly + public class StateflowsDefinitionException : StateflowsException + { + public StateflowsDefinitionException(string message) : base(message) { } + public StateflowsDefinitionException(string message, Exception innerException) : base(message, innerException) { } + } +#pragma warning restore S3925 // "ISerializable" should be implemented correctly +} diff --git a/Core/Stateflows.Common/Exceptions/StateflowsRuntimeException.cs b/Core/Stateflows.Common/Exceptions/StateflowsRuntimeException.cs new file mode 100644 index 00000000..ec8f8940 --- /dev/null +++ b/Core/Stateflows.Common/Exceptions/StateflowsRuntimeException.cs @@ -0,0 +1,12 @@ +using System; + +namespace Stateflows.Common.Exceptions +{ +#pragma warning disable S3925 // "ISerializable" should be implemented correctly + public class StateflowsRuntimeException : StateflowsException + { + public StateflowsRuntimeException(string message) : base(message) { } + public StateflowsRuntimeException(string message, Exception innerException) : base(message, innerException) { } + } +#pragma warning restore S3925 // "ISerializable" should be implemented correctly +} diff --git a/Core/Stateflows.Common/Exceptions/TransportException.cs b/Core/Stateflows.Common/Exceptions/TransportException.cs index 67b75fef..f1927e5f 100644 --- a/Core/Stateflows.Common/Exceptions/TransportException.cs +++ b/Core/Stateflows.Common/Exceptions/TransportException.cs @@ -3,7 +3,7 @@ namespace Stateflows.Common.Exceptions { #pragma warning disable S3925 // "ISerializable" should be implemented correctly - public class TransportException : StateflowsException + public class TransportException : StateflowsDefinitionException { public TransportException(string message) : base(message) { } public TransportException(string message, Exception innerException) : base(message, innerException) { } diff --git a/Core/Stateflows.Common/StateMachines/Classes/StateMachineId.cs b/Core/Stateflows.Common/StateMachines/Classes/StateMachineId.cs index 26b40639..20d22020 100644 --- a/Core/Stateflows.Common/StateMachines/Classes/StateMachineId.cs +++ b/Core/Stateflows.Common/StateMachines/Classes/StateMachineId.cs @@ -18,7 +18,7 @@ public StateMachineId(BehaviorId id) { if (id.Type != StateMachineClass.Type) { - throw new StateflowsException("BehaviorId doesn't represent State Machine"); + throw new StateflowsDefinitionException("BehaviorId doesn't represent State Machine"); } Name = id.Name; diff --git a/Core/Stateflows.Testing/StateMachines/Sequence/ExecutionSequence.cs b/Core/Stateflows.Testing/StateMachines/Sequence/ExecutionSequence.cs index 9d7c7c8e..52b451d0 100644 --- a/Core/Stateflows.Testing/StateMachines/Sequence/ExecutionSequence.cs +++ b/Core/Stateflows.Testing/StateMachines/Sequence/ExecutionSequence.cs @@ -37,7 +37,7 @@ public void ValidateWith(IExecutionSequenceBuilder sequenceBuilder) if (!found) { - throw new StateflowsException($"Expected execution step \"{entry}\" not found"); + throw new StateflowsDefinitionException($"Expected execution step \"{entry}\" not found"); } } } diff --git a/Core/Stateflows/Activities/ActivitiesDependencyInjection.cs b/Core/Stateflows/Activities/ActivitiesDependencyInjection.cs index ae5be48b..5b90b38b 100644 --- a/Core/Stateflows/Activities/ActivitiesDependencyInjection.cs +++ b/Core/Stateflows/Activities/ActivitiesDependencyInjection.cs @@ -2,8 +2,8 @@ using System.Diagnostics; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; -using Stateflows.Common; using Stateflows.Common.Interfaces; +using Stateflows.Common.Initializer; using Stateflows.Common.Registration.Interfaces; using Stateflows.Activities.Engine; using Stateflows.Activities.Context; @@ -11,7 +11,6 @@ using Stateflows.Activities.EventHandlers; using Stateflows.Activities.Registration.Builders; using Stateflows.Activities.Registration.Interfaces; -using Stateflows.Common.Initializer; namespace Stateflows.Activities { @@ -56,23 +55,19 @@ private static ActivitiesRegister EnsureActivitiesServices(this IStateflowsBuild .AddSingleton() .AddSingleton() .AddTransient(provider => - ContextHolder.ActivityContext.Value ?? + ActivitiesContextHolder.ActivityContext.Value ?? throw new InvalidOperationException($"No service for type '{typeof(IActivityContext).FullName}' is available in this context.") ) .AddTransient(provider => - ContextHolder.NodeContext.Value ?? + ActivitiesContextHolder.NodeContext.Value ?? throw new InvalidOperationException($"No service for type '{typeof(INodeContext).FullName}' is available in this context.") ) .AddTransient(provider => - ContextHolder.FlowContext.Value ?? + ActivitiesContextHolder.FlowContext.Value ?? throw new InvalidOperationException($"No service for type '{typeof(IFlowContext).FullName}' is available in this context.") ) .AddTransient(provider => - ContextHolder.ExecutionContext.Value ?? - throw new InvalidOperationException($"No service for type '{typeof(IExecutionContext).FullName}' is available in this context.") - ) - .AddTransient(provider => - ContextHolder.ExceptionContext.Value ?? + ActivitiesContextHolder.ExceptionContext.Value ?? throw new InvalidOperationException($"No service for type '{typeof(IExceptionContext).FullName}' is available in this context.") ) ; diff --git a/Core/Stateflows/Activities/Context/ContextHolder.cs b/Core/Stateflows/Activities/Context/ActivitiesContextHolder.cs similarity index 74% rename from Core/Stateflows/Activities/Context/ContextHolder.cs rename to Core/Stateflows/Activities/Context/ActivitiesContextHolder.cs index 5fe0c169..52d79ca0 100644 --- a/Core/Stateflows/Activities/Context/ContextHolder.cs +++ b/Core/Stateflows/Activities/Context/ActivitiesContextHolder.cs @@ -1,14 +1,15 @@ using System.Threading; using Stateflows.Common; +using Stateflows.Common.Context; namespace Stateflows.Activities.Context { - public static class ContextHolder + public static class ActivitiesContextHolder { public static readonly AsyncLocal ActivityContext = new AsyncLocal(); public static readonly AsyncLocal NodeContext = new AsyncLocal(); public static readonly AsyncLocal FlowContext = new AsyncLocal(); - public static readonly AsyncLocal ExecutionContext = new AsyncLocal(); + public static AsyncLocal ExecutionContext => CommonContextHolder.ExecutionContext; public static readonly AsyncLocal ExceptionContext = new AsyncLocal(); } } diff --git a/Core/Stateflows/Activities/Engine/Executor.cs b/Core/Stateflows/Activities/Engine/Executor.cs index 44ec0635..245924c4 100644 --- a/Core/Stateflows/Activities/Engine/Executor.cs +++ b/Core/Stateflows/Activities/Engine/Executor.cs @@ -557,7 +557,7 @@ public async Task DoInitializeActivityAsync(ActivityInitia } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } diff --git a/Core/Stateflows/Activities/Engine/NodeScope.cs b/Core/Stateflows/Activities/Engine/NodeScope.cs index eef606c1..ea31a9e4 100644 --- a/Core/Stateflows/Activities/Engine/NodeScope.cs +++ b/Core/Stateflows/Activities/Engine/NodeScope.cs @@ -81,11 +81,11 @@ public TDefaultInitializer GetDefaultInitializer(IActivityI ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.NodeContext.Value = null; - ContextHolder.FlowContext.Value = null; - ContextHolder.ActivityContext.Value = context.Activity; - ContextHolder.ExecutionContext.Value = context; - ContextHolder.ExceptionContext.Value = null; + ActivitiesContextHolder.NodeContext.Value = null; + ActivitiesContextHolder.FlowContext.Value = null; + ActivitiesContextHolder.ActivityContext.Value = context.Activity; + ActivitiesContextHolder.ExecutionContext.Value = context; + ActivitiesContextHolder.ExceptionContext.Value = null; var initializer = ServiceProvider.GetService(); @@ -101,11 +101,11 @@ public TInitializer GetInitializer(IActivity ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.NodeContext.Value = null; - ContextHolder.FlowContext.Value = null; - ContextHolder.ActivityContext.Value = context.Activity; - ContextHolder.ExecutionContext.Value = context; - ContextHolder.ExceptionContext.Value = null; + ActivitiesContextHolder.NodeContext.Value = null; + ActivitiesContextHolder.FlowContext.Value = null; + ActivitiesContextHolder.ActivityContext.Value = context.Activity; + ActivitiesContextHolder.ExecutionContext.Value = context; + ActivitiesContextHolder.ExceptionContext.Value = null; var initializer = ServiceProvider.GetService(); @@ -120,11 +120,11 @@ public TFinalizer GetFinalizer(IActivityActionContext context) ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.NodeContext.Value = null; - ContextHolder.FlowContext.Value = null; - ContextHolder.ActivityContext.Value = context.Activity; - ContextHolder.ExecutionContext.Value = context; - ContextHolder.ExceptionContext.Value = null; + ActivitiesContextHolder.NodeContext.Value = null; + ActivitiesContextHolder.FlowContext.Value = null; + ActivitiesContextHolder.ActivityContext.Value = context.Activity; + ActivitiesContextHolder.ExecutionContext.Value = context; + ActivitiesContextHolder.ExceptionContext.Value = null; var initializer = ServiceProvider.GetService(); @@ -139,11 +139,11 @@ public TAction GetAction(IActionContext context) ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.NodeContext.Value = context.CurrentNode; - ContextHolder.FlowContext.Value = null; - ContextHolder.ActivityContext.Value = context.Activity; - ContextHolder.ExecutionContext.Value = context; - ContextHolder.ExceptionContext.Value = null; + ActivitiesContextHolder.NodeContext.Value = context.CurrentNode; + ActivitiesContextHolder.FlowContext.Value = null; + ActivitiesContextHolder.ActivityContext.Value = context.Activity; + ActivitiesContextHolder.ExecutionContext.Value = context; + ActivitiesContextHolder.ExceptionContext.Value = null; return ServiceProvider.GetService(); } @@ -157,11 +157,11 @@ public TAcceptEventAction GetAcceptEventAction(IAcce ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.NodeContext.Value = context.CurrentNode; - ContextHolder.FlowContext.Value = null; - ContextHolder.ActivityContext.Value = context.Activity; - ContextHolder.ExecutionContext.Value = context; - ContextHolder.ExceptionContext.Value = null; + ActivitiesContextHolder.NodeContext.Value = context.CurrentNode; + ActivitiesContextHolder.FlowContext.Value = null; + ActivitiesContextHolder.ActivityContext.Value = context.Activity; + ActivitiesContextHolder.ExecutionContext.Value = context; + ActivitiesContextHolder.ExceptionContext.Value = null; return ServiceProvider.GetService(); } @@ -174,11 +174,11 @@ public TTimeEventAction GetTimeEventAction(IActionContext cont ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.NodeContext.Value = context.CurrentNode; - ContextHolder.FlowContext.Value = null; - ContextHolder.ActivityContext.Value = context.Activity; - ContextHolder.ExecutionContext.Value = context; - ContextHolder.ExceptionContext.Value = null; + ActivitiesContextHolder.NodeContext.Value = context.CurrentNode; + ActivitiesContextHolder.FlowContext.Value = null; + ActivitiesContextHolder.ActivityContext.Value = context.Activity; + ActivitiesContextHolder.ExecutionContext.Value = context; + ActivitiesContextHolder.ExceptionContext.Value = null; return ServiceProvider.GetService(); } @@ -192,11 +192,11 @@ public TSendEventAction GetSendEventAction(IActionCont ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.NodeContext.Value = context.CurrentNode; - ContextHolder.FlowContext.Value = null; - ContextHolder.ActivityContext.Value = context.Activity; - ContextHolder.ExecutionContext.Value = context; - ContextHolder.ExceptionContext.Value = null; + ActivitiesContextHolder.NodeContext.Value = context.CurrentNode; + ActivitiesContextHolder.FlowContext.Value = null; + ActivitiesContextHolder.ActivityContext.Value = context.Activity; + ActivitiesContextHolder.ExecutionContext.Value = context; + ActivitiesContextHolder.ExceptionContext.Value = null; return ServiceProvider.GetService(); } @@ -209,11 +209,11 @@ public TStructuredActivity GetStructuredActivity(IActionCon ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.NodeContext.Value = context.CurrentNode; - ContextHolder.FlowContext.Value = null; - ContextHolder.ActivityContext.Value = context.Activity; - ContextHolder.ExecutionContext.Value = context; - ContextHolder.ExceptionContext.Value = null; + ActivitiesContextHolder.NodeContext.Value = context.CurrentNode; + ActivitiesContextHolder.FlowContext.Value = null; + ActivitiesContextHolder.ActivityContext.Value = context.Activity; + ActivitiesContextHolder.ExecutionContext.Value = context; + ActivitiesContextHolder.ExceptionContext.Value = null; return ServiceProvider.GetService(); } @@ -227,11 +227,11 @@ public TExceptionHandler GetExceptionHandler(IExc ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.NodeContext.Value = context.CurrentNode; - ContextHolder.FlowContext.Value = null; - ContextHolder.ActivityContext.Value = context.Activity; - ContextHolder.ExecutionContext.Value = context; - ContextHolder.ExceptionContext.Value = context; + ActivitiesContextHolder.NodeContext.Value = context.CurrentNode; + ActivitiesContextHolder.FlowContext.Value = null; + ActivitiesContextHolder.ActivityContext.Value = context.Activity; + ActivitiesContextHolder.ExecutionContext.Value = context; + ActivitiesContextHolder.ExceptionContext.Value = context; return ServiceProvider.GetService(); } @@ -244,11 +244,11 @@ public TFlow GetFlow(IActivityFlowContext context) ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.NodeContext.Value = null; - ContextHolder.FlowContext.Value = context; - ContextHolder.ActivityContext.Value = context.Activity; - ContextHolder.ExecutionContext.Value = context; - ContextHolder.ExceptionContext.Value = null; + ActivitiesContextHolder.NodeContext.Value = null; + ActivitiesContextHolder.FlowContext.Value = context; + ActivitiesContextHolder.ActivityContext.Value = context.Activity; + ActivitiesContextHolder.ExecutionContext.Value = context; + ActivitiesContextHolder.ExceptionContext.Value = null; return ServiceProvider.GetService(); } diff --git a/Core/Stateflows/Activities/Exceptions/ActivityDefinitionException.cs b/Core/Stateflows/Activities/Exceptions/ActivityDefinitionException.cs index fcf9c4a4..bbef997c 100644 --- a/Core/Stateflows/Activities/Exceptions/ActivityDefinitionException.cs +++ b/Core/Stateflows/Activities/Exceptions/ActivityDefinitionException.cs @@ -3,7 +3,7 @@ namespace Stateflows.Activities.Exceptions { #pragma warning disable S3925 // "ISerializable" should be implemented correctly - public class ActivityDefinitionException : StateflowsException + public class ActivityDefinitionException : StateflowsDefinitionException { public ActivityDefinitionException(string message) : base(message) { } } diff --git a/Core/Stateflows/Activities/Exceptions/ActivityException.cs b/Core/Stateflows/Activities/Exceptions/ActivityException.cs index 7a41446f..3eb4702c 100644 --- a/Core/Stateflows/Activities/Exceptions/ActivityException.cs +++ b/Core/Stateflows/Activities/Exceptions/ActivityException.cs @@ -3,7 +3,7 @@ namespace Stateflows.Activities.Exceptions { #pragma warning disable S3925 // "ISerializable" should be implemented correctly - public class ActivityException : StateflowsException + public class ActivityException : StateflowsDefinitionException { public ActivityException(string message) : base(message) { } } diff --git a/Core/Stateflows/Activities/Models/Graph.cs b/Core/Stateflows/Activities/Models/Graph.cs index e7e2f7f0..b6562912 100644 --- a/Core/Stateflows/Activities/Models/Graph.cs +++ b/Core/Stateflows/Activities/Models/Graph.cs @@ -17,8 +17,11 @@ public Graph(string name, int version) Type = NodeType.Activity; Version = version; Level = 0; + Class = new ActivityClass(Name); } + public ActivityClass Class { get; } + public int Version { get; } public Type ActivityType { get; set; } public bool Interactive { get; set; } = false; diff --git a/Core/Stateflows/Activities/Registration/Builders/ActivityBuilder.cs b/Core/Stateflows/Activities/Registration/Builders/ActivityBuilder.cs index 65d590e4..4046ced6 100644 --- a/Core/Stateflows/Activities/Registration/Builders/ActivityBuilder.cs +++ b/Core/Stateflows/Activities/Registration/Builders/ActivityBuilder.cs @@ -92,7 +92,7 @@ public IActivityBuilder AddInitializer(Func action } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } @@ -362,7 +362,7 @@ public BaseActivityBuilder AddOnInitialize(Func acti } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } diff --git a/Core/Stateflows/Activities/Registration/Builders/FlowBuilder.cs b/Core/Stateflows/Activities/Registration/Builders/FlowBuilder.cs index 418dda7d..669884cd 100644 --- a/Core/Stateflows/Activities/Registration/Builders/FlowBuilder.cs +++ b/Core/Stateflows/Activities/Registration/Builders/FlowBuilder.cs @@ -44,7 +44,7 @@ await guardAsync(new TokenFlowContext(context, token.Payload)) } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } @@ -85,7 +85,7 @@ context.Token is TokenHolder token } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } diff --git a/Core/Stateflows/Activities/StateMachines/Extensions/CompositeStateBuilderExtensions.cs b/Core/Stateflows/Activities/StateMachines/Extensions/CompositeStateBuilderExtensions.cs index ef31a53c..db16edbd 100644 --- a/Core/Stateflows/Activities/StateMachines/Extensions/CompositeStateBuilderExtensions.cs +++ b/Core/Stateflows/Activities/StateMachines/Extensions/CompositeStateBuilderExtensions.cs @@ -1,10 +1,6 @@ -using System.Threading.Tasks; -using Stateflows.Common; -using Stateflows.Common.Classes; +using System.Diagnostics; using Stateflows.StateMachines.Sync; -using Stateflows.Activities.Events; using Stateflows.Activities.Extensions; -using Stateflows.Activities.StateMachines.Interfaces; using Stateflows.StateMachines.Registration; using Stateflows.StateMachines.Registration.Interfaces; @@ -12,58 +8,20 @@ namespace Stateflows.Activities { public static class CompositeStateBuilderExtensions { + [DebuggerHidden] public static ICompositeStateBuilder AddOnEntryActivity(this ICompositeStateBuilder builder, string activityName, StateActionActivityBuildAction buildAction = null) - => builder - .AddOnEntry( - c => - { - if (c.TryLocateActivity(activityName, $"{c.StateMachine.Id.Instance}.{c.CurrentState.Name}.{Constants.Entry}.{c.ExecutionTrigger.Id}", out var a)) - { - Task.Run(async () => - { - var integratedActivityBuilder = new StateActionActivityBuilder(buildAction); - Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) - ? await integratedActivityBuilder.InitializationBuilder(c) - : new Initialize(); - return a.SendCompoundAsync( - integratedActivityBuilder.GetSubscriptionRequest(c.StateMachine.Id), - new SetGlobalValues() { Values = (c.StateMachine.Values as ContextValuesCollection).Values }, - new ExecutionRequest() { InitializationEvent = initializationEvent }, - integratedActivityBuilder.GetUnsubscriptionRequest(c.StateMachine.Id) - ); - }); - } - } - ); + => builder.AddOnEntry(c => StateMachineActivityExtensions.RunStateActivity(Constants.Entry, c, activityName, buildAction)); + [DebuggerHidden] public static ICompositeStateBuilder AddOnEntryActivity(this ICompositeStateBuilder builder, StateActionActivityBuildAction buildAction = null) where TActivity : class, IActivity => AddOnEntryActivity(builder, Activity.Name, buildAction); + [DebuggerHidden] public static ICompositeStateBuilder AddOnExitActivity(this ICompositeStateBuilder builder, string activityName, StateActionActivityBuildAction buildAction = null) - => builder - .AddOnExit( - c => - { - if (c.TryLocateActivity(activityName, $"{c.StateMachine.Id.Instance}.{c.CurrentState.Name}.{Constants.Exit}.{c.ExecutionTrigger.Id}", out var a)) - { - Task.Run(async () => - { - var integratedActivityBuilder = new StateActionActivityBuilder(buildAction); - Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) - ? await integratedActivityBuilder.InitializationBuilder(c) - : new Initialize(); - return a.SendCompoundAsync( - integratedActivityBuilder.GetSubscriptionRequest(c.StateMachine.Id), - new SetGlobalValues() { Values = (c.StateMachine.Values as ContextValuesCollection).Values }, - new ExecutionRequest() { InitializationEvent = initializationEvent }, - integratedActivityBuilder.GetUnsubscriptionRequest(c.StateMachine.Id) - ); - }); - } - } - ); + => builder.AddOnExit(c => StateMachineActivityExtensions.RunStateActivity(Constants.Exit, c, activityName, buildAction)); + [DebuggerHidden] public static ICompositeStateBuilder AddOnExitActivity(this ICompositeStateBuilder builder, StateActionActivityBuildAction buildAction = null) where TActivity : class, IActivity => AddOnExitActivity(builder, Activity.Name, buildAction); diff --git a/Core/Stateflows/Activities/StateMachines/Extensions/DefaultTransitionBuilderExtensions.cs b/Core/Stateflows/Activities/StateMachines/Extensions/DefaultTransitionBuilderExtensions.cs index e2889a18..dd122f39 100644 --- a/Core/Stateflows/Activities/StateMachines/Extensions/DefaultTransitionBuilderExtensions.cs +++ b/Core/Stateflows/Activities/StateMachines/Extensions/DefaultTransitionBuilderExtensions.cs @@ -1,15 +1,7 @@ -using System.Linq; -using System.Diagnostics; -using System.Threading.Tasks; -using Stateflows.Common; -using Stateflows.Common.Classes; -using Stateflows.Activities.Events; +using System.Diagnostics; using Stateflows.Activities.Extensions; -using Stateflows.Activities.StateMachines.Interfaces; using Stateflows.StateMachines.Events; -using Stateflows.StateMachines.Registration; using Stateflows.StateMachines.Registration.Interfaces; -using Stateflows.Common.Utilities; namespace Stateflows.Activities { @@ -18,36 +10,7 @@ public static class DefaultTransitionBuilderExtensions #region AddGuardActivity [DebuggerHidden] public static IDefaultTransitionBuilder AddGuardActivity(this IDefaultTransitionBuilder builder, string activityName, TransitionActivityBuildAction buildAction = null) - => builder.AddGuard( - async c => - { - var result = false; - if (c.TryLocateActivity(activityName, $"{c.StateMachine.Id.Instance}.{c.SourceState.Name}.{Constants.Guard}.{c.Event.Id}", out var a)) - { - var ev = StateflowsJsonConverter.Clone(c.Event); - await Task.Run(async () => - { - var integratedActivityBuilder = new TransitionActivityBuilder(buildAction); - Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) - ? await integratedActivityBuilder.InitializationBuilder(c) - : new Initialize(); - var executionRequest = new ExecutionRequest() { InitializationEvent = initializationEvent }; - executionRequest.AddInputToken(ev); - - var sendResult = await a.SendCompoundAsync( - integratedActivityBuilder.GetSubscriptionRequest(c.StateMachine.Id), - new SetGlobalValues() { Values = (c.StateMachine.Values as ContextValuesCollection).Values }, - executionRequest, - integratedActivityBuilder.GetUnsubscriptionRequest(c.StateMachine.Id) - ); - - result = (sendResult.Response.Results.Skip(2).Take(1).First().Response as ExecutionResponse).OutputTokens.OfType>().FirstOrDefault()?.Payload ?? false; - }); - } - - return result; - } - ); + => builder.AddGuard(c => StateMachineActivityExtensions.RunGuardActivity(c, activityName, buildAction)); [DebuggerHidden] public static IDefaultTransitionBuilder AddGuardActivity(this IDefaultTransitionBuilder builder, TransitionActivityBuildAction buildAction = null) @@ -58,37 +21,7 @@ public static IDefaultTransitionBuilder AddGuardActivity(this #region AddEffectActivity [DebuggerHidden] public static IDefaultTransitionBuilder AddEffectActivity(this IDefaultTransitionBuilder builder, string activityName, TransitionActivityBuildAction buildAction = null) - => builder.AddEffect( - c => - { - if (c.TryLocateActivity(activityName, $"{c.StateMachine.Id.Instance}.{c.SourceState.Name}.{Constants.Effect}.{c.Event.Id}", out var a)) - { - var ev = StateflowsJsonConverter.Clone(c.Event); - Task.Run(async () => - { - var integratedActivityBuilder = new TransitionActivityBuilder(buildAction); - Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) - ? await integratedActivityBuilder.InitializationBuilder(c) - : new Initialize(); - var executionRequest = new ExecutionRequest() { InitializationEvent = initializationEvent }; - executionRequest.AddInputToken(ev); - - return a.SendCompoundAsync( - integratedActivityBuilder.GetSubscriptionRequest(c.StateMachine.Id), - new SetGlobalValues() { Values = (c.StateMachine.Values as ContextValuesCollection).Values }, - executionRequest, - integratedActivityBuilder.GetUnsubscriptionRequest(c.StateMachine.Id) - ); - }); - - return Task.CompletedTask; - } - else - { - return Task.CompletedTask; - } - } - ); + => builder.AddEffect(c => StateMachineActivityExtensions.RunEffectActivity(c, activityName, buildAction)); [DebuggerHidden] public static IDefaultTransitionBuilder AddEffectActivity(this IDefaultTransitionBuilder builder, TransitionActivityBuildAction buildAction = null) diff --git a/Core/Stateflows/Activities/StateMachines/Extensions/InternalTransitionBuilderExtensions.cs b/Core/Stateflows/Activities/StateMachines/Extensions/InternalTransitionBuilderExtensions.cs index 90c5068c..6848673d 100644 --- a/Core/Stateflows/Activities/StateMachines/Extensions/InternalTransitionBuilderExtensions.cs +++ b/Core/Stateflows/Activities/StateMachines/Extensions/InternalTransitionBuilderExtensions.cs @@ -1,14 +1,7 @@ -using System.Linq; -using System.Diagnostics; -using System.Threading.Tasks; +using System.Diagnostics; using Stateflows.Common; -using Stateflows.Common.Classes; using Stateflows.Activities.Extensions; -using Stateflows.StateMachines.Registration; using Stateflows.StateMachines.Registration.Interfaces; -using Stateflows.Activities.Events; -using Stateflows.Activities.StateMachines.Interfaces; -using Stateflows.Common.Utilities; namespace Stateflows.Activities { @@ -18,81 +11,26 @@ public static class InternalTransitionBuilderExtensions [DebuggerHidden] public static IInternalTransitionBuilder AddGuardActivity(this IInternalTransitionBuilder builder, string activityName, TransitionActivityBuildAction buildAction = null) where TEvent : Event, new() - => builder.AddGuard( - async c => - { - var result = false; - if (c.TryLocateActivity(activityName, $"{c.StateMachine.Id.Instance}.{c.SourceState.Name}.{EventInfo.Name}.{Constants.Guard}.{c.Event.Id}", out var a)) - { - var ev = StateflowsJsonConverter.Clone(c.Event); - await Task.Run(async () => - { - var integratedActivityBuilder = new TransitionActivityBuilder(buildAction); - Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) - ? await integratedActivityBuilder.InitializationBuilder(c) - : new Initialize(); - var executionRequest = new ExecutionRequest() { InitializationEvent = initializationEvent }; - executionRequest.AddInputToken(ev); - - var sendResult = await a.SendCompoundAsync( - integratedActivityBuilder.GetSubscriptionRequest(c.StateMachine.Id), - new SetGlobalValues() { Values = (c.StateMachine.Values as ContextValuesCollection).Values }, - executionRequest, - integratedActivityBuilder.GetUnsubscriptionRequest(c.StateMachine.Id) - ); - - result = (sendResult.Response.Results.Skip(2).Take(1).First().Response as ExecutionResponse).OutputTokens.OfType>().FirstOrDefault()?.Payload ?? false; - }); - } - - return result; - } - ); + => builder.AddGuard(c => StateMachineActivityExtensions.RunGuardActivity(c, activityName, buildAction)); [DebuggerHidden] public static IInternalTransitionBuilder AddGuardActivity(this IInternalTransitionBuilder builder, TransitionActivityBuildAction buildAction = null) where TEvent : Event, new() where TActivity : class, IActivity - => builder.AddGuardActivity(Activity.Name, buildAction); + => builder.AddGuardActivity(Activity.Name, buildAction); #endregion #region AddEffectActivity [DebuggerHidden] public static IInternalTransitionBuilder AddEffectActivity(this IInternalTransitionBuilder builder, string activityName, TransitionActivityBuildAction buildAction = null) where TEvent : Event, new() - => builder.AddEffect( - c => - { - if (c.TryLocateActivity(activityName, $"{c.StateMachine.Id.Instance}.{c.SourceState.Name}.{EventInfo.Name}.{Constants.Effect}.{c.Event.Id}", out var a)) - { - var ev = StateflowsJsonConverter.Clone(c.Event); - Task.Run(async () => - { - var integratedActivityBuilder = new TransitionActivityBuilder(buildAction); - Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) - ? await integratedActivityBuilder.InitializationBuilder(c) - : new Initialize(); - var executionRequest = new ExecutionRequest() { InitializationEvent = initializationEvent }; - executionRequest.AddInputToken(ev); - - return a.SendCompoundAsync( - integratedActivityBuilder.GetSubscriptionRequest(c.StateMachine.Id), - new SetGlobalValues() { Values = (c.StateMachine.Values as ContextValuesCollection).Values }, - executionRequest, - integratedActivityBuilder.GetUnsubscriptionRequest(c.StateMachine.Id) - ); - }); - } - - return Task.CompletedTask; - } - ); + => builder.AddEffect(c => StateMachineActivityExtensions.RunEffectActivity(c, activityName, buildAction)); [DebuggerHidden] public static IInternalTransitionBuilder AddEffectActivity(this IInternalTransitionBuilder builder, TransitionActivityBuildAction buildAction = null) where TEvent : Event, new() where TActivity : class, IActivity - => builder.AddEffectActivity(Activity.Name, buildAction); + => builder.AddEffectActivity(Activity.Name, buildAction); #endregion } } \ No newline at end of file diff --git a/Core/Stateflows/Activities/StateMachines/Extensions/StateBuilderExtensions.cs b/Core/Stateflows/Activities/StateMachines/Extensions/StateBuilderExtensions.cs index 21c637db..5dec18c9 100644 --- a/Core/Stateflows/Activities/StateMachines/Extensions/StateBuilderExtensions.cs +++ b/Core/Stateflows/Activities/StateMachines/Extensions/StateBuilderExtensions.cs @@ -1,11 +1,6 @@ -using System.Threading.Tasks; -using System.Collections.Generic; -using Stateflows.Common; -using Stateflows.Common.Classes; +using System.Diagnostics; using Stateflows.StateMachines.Sync; -using Stateflows.Activities.Events; using Stateflows.Activities.Extensions; -using Stateflows.Activities.StateMachines.Interfaces; using Stateflows.StateMachines.Registration; using Stateflows.StateMachines.Registration.Interfaces; @@ -13,60 +8,20 @@ namespace Stateflows.Activities { public static class StateBuilderExtensions { - internal static readonly List DoActivites = new List(); - + [DebuggerHidden] public static IStateBuilder AddOnEntryActivity(this IStateBuilder builder, string activityName, StateActionActivityBuildAction buildAction = null) - => builder - .AddOnEntry( - c => - { - if (c.TryLocateActivity(activityName, $"{c.StateMachine.Id.Instance}.{c.CurrentState.Name}.{Constants.Entry}.{c.ExecutionTrigger.Id}", out var a)) - { - Task.Run(async () => - { - var integratedActivityBuilder = new StateActionActivityBuilder(buildAction); - Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) - ? await integratedActivityBuilder.InitializationBuilder(c) - : new Initialize(); - return a.SendCompoundAsync( - integratedActivityBuilder.GetSubscriptionRequest(c.StateMachine.Id), - new SetGlobalValues() { Values = (c.StateMachine.Values as ContextValuesCollection).Values }, - new ExecutionRequest() { InitializationEvent = initializationEvent }, - integratedActivityBuilder.GetUnsubscriptionRequest(c.StateMachine.Id) - ); - }); - } - } - ); + => builder.AddOnEntry(c => StateMachineActivityExtensions.RunStateActivity(Constants.Entry, c, activityName, buildAction)); + [DebuggerHidden] public static IStateBuilder AddOnEntryActivity(this IStateBuilder builder, StateActionActivityBuildAction buildAction = null) where TActivity : class, IActivity => AddOnEntryActivity(builder, Activity.Name, buildAction); + [DebuggerHidden] public static IStateBuilder AddOnExitActivity(this IStateBuilder builder, string activityName, StateActionActivityBuildAction buildAction = null) - => builder - .AddOnExit( - c => - { - if (c.TryLocateActivity(activityName, $"{c.StateMachine.Id.Instance}.{c.CurrentState.Name}.{Constants.Exit}.{c.ExecutionTrigger.Id}", out var a)) - { - Task.Run(async () => - { - var integratedActivityBuilder = new StateActionActivityBuilder(buildAction); - Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) - ? await integratedActivityBuilder.InitializationBuilder(c) - : new Initialize(); - return a.SendCompoundAsync( - integratedActivityBuilder.GetSubscriptionRequest(c.StateMachine.Id), - new SetGlobalValues() { Values = (c.StateMachine.Values as ContextValuesCollection).Values }, - new ExecutionRequest() { InitializationEvent = initializationEvent }, - integratedActivityBuilder.GetUnsubscriptionRequest(c.StateMachine.Id) - ); - }); - } - } - ); + => builder.AddOnExit(c => StateMachineActivityExtensions.RunStateActivity(Constants.Exit, c, activityName, buildAction)); + [DebuggerHidden] public static IStateBuilder AddOnExitActivity(this IStateBuilder builder, StateActionActivityBuildAction buildAction = null) where TActivity : class, IActivity => AddOnExitActivity(builder, Activity.Name, buildAction); diff --git a/Core/Stateflows/Activities/StateMachines/Extensions/StateMachineActivityExtensions.cs b/Core/Stateflows/Activities/StateMachines/Extensions/StateMachineActivityExtensions.cs new file mode 100644 index 00000000..bc18fd60 --- /dev/null +++ b/Core/Stateflows/Activities/StateMachines/Extensions/StateMachineActivityExtensions.cs @@ -0,0 +1,110 @@ +using System.Linq; +using System.Diagnostics; +using System.Threading.Tasks; +using Stateflows.Common; +using Stateflows.Common.Classes; +using Stateflows.Common.Utilities; +using Stateflows.Activities.Events; +using Stateflows.Activities.Extensions; +using Stateflows.Activities.StateMachines.Interfaces; +using Stateflows.StateMachines.Exceptions; +using Stateflows.StateMachines.Registration; +using Stateflows.StateMachines.Context.Interfaces; + +namespace Stateflows.Activities +{ + public static class StateMachineActivityExtensions + { + [DebuggerHidden] + internal static void RunStateActivity(string actionName, IStateActionContext context, string activityName, StateActionActivityBuildAction buildAction) + { + if (context.TryLocateActivity(activityName, $"{context.StateMachine.Id.Instance}.{context.CurrentState.Name}.{actionName}.{context.ExecutionTrigger.Id}", out var a)) + { + Task.Run(async () => + { + var integratedActivityBuilder = new StateActionActivityBuilder(buildAction); + Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) + ? await integratedActivityBuilder.InitializationBuilder(context) + : new Initialize(); + return a.SendCompoundAsync( + integratedActivityBuilder.GetSubscriptionRequest(context.StateMachine.Id), + new SetGlobalValues() { Values = (context.StateMachine.Values as ContextValuesCollection).Values }, + new ExecutionRequest() { InitializationEvent = initializationEvent }, + integratedActivityBuilder.GetUnsubscriptionRequest(context.StateMachine.Id) + ); + }); + } + else + { + throw new StateMachineRuntimeException($"On{actionName}Activity '{activityName}' not found", context.StateMachine.Id.StateMachineClass); + } + } + + [DebuggerHidden] + internal static async Task RunGuardActivity(ITransitionContext context, string activityName, TransitionActivityBuildAction buildAction) + where TEvent : Event, new() + { + var result = false; + if (context.TryLocateActivity(activityName, $"{context.StateMachine.Id.Instance}.{context.SourceState.Name}.{Constants.Guard}.{context.Event.Id}", out var a)) + { + var ev = StateflowsJsonConverter.Clone(context.Event); + await Task.Run(async () => + { + var integratedActivityBuilder = new TransitionActivityBuilder(buildAction); + Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) + ? await integratedActivityBuilder.InitializationBuilder(context) + : new Initialize(); + var executionRequest = new ExecutionRequest() { InitializationEvent = initializationEvent }; + executionRequest.AddInputToken(ev); + + var sendResult = await a.SendCompoundAsync( + integratedActivityBuilder.GetSubscriptionRequest(context.StateMachine.Id), + new SetGlobalValues() { Values = (context.StateMachine.Values as ContextValuesCollection).Values }, + executionRequest, + integratedActivityBuilder.GetUnsubscriptionRequest(context.StateMachine.Id) + ); + + result = (sendResult.Response.Results.Skip(2).Take(1).First().Response as ExecutionResponse).OutputTokens.OfType>().FirstOrDefault()?.Payload ?? false; + }); + } + else + { + throw new StateMachineRuntimeException($"GuardActivity '{activityName}' not found", context.StateMachine.Id.StateMachineClass); + } + + return result; + } + + [DebuggerHidden] + internal static Task RunEffectActivity(ITransitionContext context, string activityName, TransitionActivityBuildAction buildAction) + where TEvent : Event, new() + { + if (context.TryLocateActivity(activityName, $"{context.StateMachine.Id.Instance}.{context.SourceState.Name}.{EventInfo.Name}.{Constants.Effect}.{context.Event.Id}", out var a)) + { + var ev = StateflowsJsonConverter.Clone(context.Event); + Task.Run(async () => + { + var integratedActivityBuilder = new TransitionActivityBuilder(buildAction); + Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) + ? await integratedActivityBuilder.InitializationBuilder(context) + : new Initialize(); + var executionRequest = new ExecutionRequest() { InitializationEvent = initializationEvent }; + executionRequest.AddInputToken(ev); + + return a.SendCompoundAsync( + integratedActivityBuilder.GetSubscriptionRequest(context.StateMachine.Id), + new SetGlobalValues() { Values = (context.StateMachine.Values as ContextValuesCollection).Values }, + executionRequest, + integratedActivityBuilder.GetUnsubscriptionRequest(context.StateMachine.Id) + ); + }); + } + else + { + throw new StateMachineRuntimeException($"EffectActivity '{activityName}' not found", context.StateMachine.Id.StateMachineClass); + } + + return Task.CompletedTask; + } + } +} diff --git a/Core/Stateflows/Activities/StateMachines/Extensions/TransitionBuilderExtensions.cs b/Core/Stateflows/Activities/StateMachines/Extensions/TransitionBuilderExtensions.cs index 9b21a4b2..d2aea9ea 100644 --- a/Core/Stateflows/Activities/StateMachines/Extensions/TransitionBuilderExtensions.cs +++ b/Core/Stateflows/Activities/StateMachines/Extensions/TransitionBuilderExtensions.cs @@ -1,14 +1,7 @@ -using System.Linq; -using System.Diagnostics; -using System.Threading.Tasks; +using System.Diagnostics; using Stateflows.Common; -using Stateflows.Common.Classes; -using Stateflows.StateMachines.Registration; -using Stateflows.StateMachines.Registration.Interfaces; -using Stateflows.Activities.Events; using Stateflows.Activities.Extensions; -using Stateflows.Activities.StateMachines.Interfaces; -using Stateflows.Common.Utilities; +using Stateflows.StateMachines.Registration.Interfaces; namespace Stateflows.Activities { @@ -18,81 +11,26 @@ public static class TransitionBuilderExtensions [DebuggerHidden] public static ITransitionBuilder AddGuardActivity(this ITransitionBuilder builder, string activityName, TransitionActivityBuildAction buildAction = null) where TEvent : Event, new() - => builder.AddGuard( - async c => - { - var result = false; - if (c.TryLocateActivity(activityName, $"{c.StateMachine.Id.Instance}.{c.SourceState.Name}.{EventInfo.Name}.{Constants.Guard}.{c.Event.Id}", out var a)) - { - var ev = StateflowsJsonConverter.Clone(c.Event); - await Task.Run(async () => - { - var integratedActivityBuilder = new TransitionActivityBuilder(buildAction); - Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) - ? await integratedActivityBuilder.InitializationBuilder(c) - : new Initialize(); - var executionRequest = new ExecutionRequest() { InitializationEvent = initializationEvent }; - executionRequest.AddInputToken(ev); - - var sendResult = await a.SendCompoundAsync( - integratedActivityBuilder.GetSubscriptionRequest(c.StateMachine.Id), - new SetGlobalValues() { Values = (c.StateMachine.Values as ContextValuesCollection).Values }, - executionRequest, - integratedActivityBuilder.GetUnsubscriptionRequest(c.StateMachine.Id) - ); - - result = (sendResult.Response.Results.Skip(2).Take(1).First()?.Response as ExecutionResponse)?.OutputTokens?.OfType>()?.FirstOrDefault()?.Payload ?? false; - }); - } - - return result; - } - ); + => builder.AddGuard(c => StateMachineActivityExtensions.RunGuardActivity(c, activityName, buildAction)); [DebuggerHidden] public static ITransitionBuilder AddGuardActivity(this ITransitionBuilder builder, TransitionActivityBuildAction buildAction = null) where TEvent : Event, new() where TActivity : class, IActivity - => builder.AddGuardActivity(Activity.Name, buildAction); + => builder.AddGuardActivity(Activity.Name, buildAction); #endregion #region AddEffectActivity [DebuggerHidden] public static ITransitionBuilder AddEffectActivity(this ITransitionBuilder builder, string activityName, TransitionActivityBuildAction buildAction = null) where TEvent : Event, new() - => builder.AddEffect( - c => - { - if (c.TryLocateActivity(activityName, $"{c.StateMachine.Id.Instance}.{c.SourceState.Name}.{EventInfo.Name}.{Constants.Effect}.{c.Event.Id}", out var a)) - { - var ev = StateflowsJsonConverter.Clone(c.Event); - Task.Run(async () => - { - var integratedActivityBuilder = new TransitionActivityBuilder(buildAction); - Event initializationEvent = (integratedActivityBuilder.InitializationBuilder != null) - ? await integratedActivityBuilder.InitializationBuilder(c) - : new Initialize(); - var executionRequest = new ExecutionRequest() { InitializationEvent = initializationEvent }; - executionRequest.AddInputToken(ev); - - return a.SendCompoundAsync( - integratedActivityBuilder.GetSubscriptionRequest(c.StateMachine.Id), - new SetGlobalValues() { Values = (c.StateMachine.Values as ContextValuesCollection).Values }, - executionRequest, - integratedActivityBuilder.GetUnsubscriptionRequest(c.StateMachine.Id) - ); - }); - } - - return Task.CompletedTask; - } - ); + => builder.AddEffect(c => StateMachineActivityExtensions.RunEffectActivity(c, activityName, buildAction)); [DebuggerHidden] public static ITransitionBuilder AddEffectActivity(this ITransitionBuilder builder, TransitionActivityBuildAction buildAction = null) where TEvent : Event, new() where TActivity : class, IActivity - => builder.AddEffectActivity(Activity.Name, buildAction); + => builder.AddEffectActivity(Activity.Name, buildAction); #endregion } } \ No newline at end of file diff --git a/Core/Stateflows/Common/Classes/BaseValueAccessor.cs b/Core/Stateflows/Common/Classes/BaseValueAccessor.cs index 2c821785..275c4590 100644 --- a/Core/Stateflows/Common/Classes/BaseValueAccessor.cs +++ b/Core/Stateflows/Common/Classes/BaseValueAccessor.cs @@ -12,7 +12,7 @@ public class BaseValueAccessor public BaseValueAccessor(string valueName, Func valueSetSelector, string collectionName) { this.valueName = valueName; - this.valueSet = valueSetSelector?.Invoke() ?? throw new StateflowsException($"{collectionName} set is not available in current context"); + this.valueSet = valueSetSelector?.Invoke() ?? throw new StateflowsDefinitionException($"{collectionName} set is not available in current context"); } public void Set(T value) diff --git a/Core/Stateflows/Common/Context/CommonContextHolder.cs b/Core/Stateflows/Common/Context/CommonContextHolder.cs new file mode 100644 index 00000000..eb12d782 --- /dev/null +++ b/Core/Stateflows/Common/Context/CommonContextHolder.cs @@ -0,0 +1,9 @@ +using System.Threading; + +namespace Stateflows.Common.Context +{ + public static class CommonContextHolder + { + public static readonly AsyncLocal ExecutionContext = new AsyncLocal(); + } +} diff --git a/Core/Stateflows/DependencyInjection.cs b/Core/Stateflows/DependencyInjection.cs index cfbc35cf..00d5617e 100644 --- a/Core/Stateflows/DependencyInjection.cs +++ b/Core/Stateflows/DependencyInjection.cs @@ -6,6 +6,7 @@ using Stateflows.Common.Tenant; using Stateflows.Common.Engine; using Stateflows.Common.Storage; +using Stateflows.Common.Context; using Stateflows.Common.Scheduler; using Stateflows.Common.Extensions; using Stateflows.Common.Interfaces; @@ -35,6 +36,10 @@ internal static IStateflowsBuilder EnsureStateflowServices(this IStateflowsBuild .AddSingleton() .AddScoped() .AddScoped() + .AddTransient(provider => + CommonContextHolder.ExecutionContext.Value ?? + throw new InvalidOperationException($"No service for type '{typeof(IExecutionContext).FullName}' is available in this context.") + ) ; } diff --git a/Core/Stateflows/StateMachines/Context/ContextHolder.cs b/Core/Stateflows/StateMachines/Context/StateMachinesContextHolder.cs similarity index 70% rename from Core/Stateflows/StateMachines/Context/ContextHolder.cs rename to Core/Stateflows/StateMachines/Context/StateMachinesContextHolder.cs index a2df1c47..854e63cb 100644 --- a/Core/Stateflows/StateMachines/Context/ContextHolder.cs +++ b/Core/Stateflows/StateMachines/Context/StateMachinesContextHolder.cs @@ -1,13 +1,14 @@ using System.Threading; using Stateflows.Common; +using Stateflows.Common.Context; namespace Stateflows.StateMachines.Context { - public static class ContextHolder + public static class StateMachinesContextHolder { public static readonly AsyncLocal StateMachineContext = new AsyncLocal(); public static readonly AsyncLocal StateContext = new AsyncLocal(); public static readonly AsyncLocal TransitionContext = new AsyncLocal(); - public static readonly AsyncLocal ExecutionContext = new AsyncLocal(); + public static AsyncLocal ExecutionContext => CommonContextHolder.ExecutionContext; } } diff --git a/Core/Stateflows/StateMachines/Engine/Executor.cs b/Core/Stateflows/StateMachines/Engine/Executor.cs index ec4f29e6..989b6a8c 100644 --- a/Core/Stateflows/StateMachines/Engine/Executor.cs +++ b/Core/Stateflows/StateMachines/Engine/Executor.cs @@ -664,10 +664,10 @@ public TDefaultInitializer GetDefaultInitializer(IStateMach ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.StateContext.Value = null; - ContextHolder.TransitionContext.Value = null; - ContextHolder.StateMachineContext.Value = context.StateMachine; - ContextHolder.ExecutionContext.Value = context; + StateMachinesContextHolder.StateContext.Value = null; + StateMachinesContextHolder.TransitionContext.Value = null; + StateMachinesContextHolder.StateMachineContext.Value = context.StateMachine; + StateMachinesContextHolder.ExecutionContext.Value = context; var initializer = ServiceProvider.GetService(); @@ -683,10 +683,10 @@ public TInitializer GetInitializer(IStateMac ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.StateContext.Value = null; - ContextHolder.TransitionContext.Value = null; - ContextHolder.StateMachineContext.Value = context.StateMachine; - ContextHolder.ExecutionContext.Value = context; + StateMachinesContextHolder.StateContext.Value = null; + StateMachinesContextHolder.TransitionContext.Value = null; + StateMachinesContextHolder.StateMachineContext.Value = context.StateMachine; + StateMachinesContextHolder.ExecutionContext.Value = context; var initializer = ServiceProvider.GetService(); @@ -701,10 +701,10 @@ public TFinalizer GetFinalizer(IStateMachineActionContext context) ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.StateContext.Value = null; - ContextHolder.TransitionContext.Value = null; - ContextHolder.StateMachineContext.Value = context.StateMachine; - ContextHolder.ExecutionContext.Value = context; + StateMachinesContextHolder.StateContext.Value = null; + StateMachinesContextHolder.TransitionContext.Value = null; + StateMachinesContextHolder.StateMachineContext.Value = context.StateMachine; + StateMachinesContextHolder.ExecutionContext.Value = context; var initializer = ServiceProvider.GetService(); @@ -719,10 +719,10 @@ public TState GetState(IStateActionContext context) ContextValues.SourceStateValuesHolder.Value = null; ContextValues.TargetStateValuesHolder.Value = null; - ContextHolder.StateContext.Value = context.CurrentState; - ContextHolder.TransitionContext.Value = null; - ContextHolder.StateMachineContext.Value = context.StateMachine; - ContextHolder.ExecutionContext.Value = context; + StateMachinesContextHolder.StateContext.Value = context.CurrentState; + StateMachinesContextHolder.TransitionContext.Value = null; + StateMachinesContextHolder.StateMachineContext.Value = context.StateMachine; + StateMachinesContextHolder.ExecutionContext.Value = context; var state = ServiceProvider.GetService(); @@ -738,10 +738,10 @@ public TTransition GetTransition(ITransitionContext ContextValues.SourceStateValuesHolder.Value = context.SourceState.Values; ContextValues.TargetStateValuesHolder.Value = context.TargetState?.Values; - ContextHolder.StateContext.Value = null; - ContextHolder.TransitionContext.Value = context; - ContextHolder.StateMachineContext.Value = context.StateMachine; - ContextHolder.ExecutionContext.Value = context; + StateMachinesContextHolder.StateContext.Value = null; + StateMachinesContextHolder.TransitionContext.Value = context; + StateMachinesContextHolder.StateMachineContext.Value = context.StateMachine; + StateMachinesContextHolder.ExecutionContext.Value = context; var transition = ServiceProvider.GetService(); @@ -756,10 +756,10 @@ public TDefaultTransition GetDefaultTransition(ITransitionCo ContextValues.SourceStateValuesHolder.Value = context.SourceState.Values; ContextValues.TargetStateValuesHolder.Value = context.TargetState?.Values; - ContextHolder.StateContext.Value = null; - ContextHolder.TransitionContext.Value = context; - ContextHolder.StateMachineContext.Value = context.StateMachine; - ContextHolder.ExecutionContext.Value = context; + StateMachinesContextHolder.StateContext.Value = null; + StateMachinesContextHolder.TransitionContext.Value = context; + StateMachinesContextHolder.StateMachineContext.Value = context.StateMachine; + StateMachinesContextHolder.ExecutionContext.Value = context; var transition = ServiceProvider.GetService(); diff --git a/Core/Stateflows/StateMachines/Engine/Plugins/Behaviors.cs b/Core/Stateflows/StateMachines/Engine/Plugins/Behaviors.cs index 1b69b195..76a14f30 100644 --- a/Core/Stateflows/StateMachines/Engine/Plugins/Behaviors.cs +++ b/Core/Stateflows/StateMachines/Engine/Plugins/Behaviors.cs @@ -1,6 +1,7 @@ using System.Linq; using System.Threading.Tasks; using Stateflows.Common; +using Stateflows.StateMachines.Exceptions; using Stateflows.StateMachines.Context.Classes; using Stateflows.StateMachines.Context.Interfaces; @@ -33,6 +34,10 @@ public async Task AfterStateEntryAsync(IStateActionContext context) _ = behavior.SendAsync(initializationRequest); } + else + { + throw new StateDefinitionException(context.CurrentState.Name, $"DoActivity '{vertex.BehaviorName}' not found", context.StateMachine.Id.StateMachineClass); + } } } diff --git a/Core/Stateflows/StateMachines/Exceptions/StateMachineDefinitionException.cs b/Core/Stateflows/StateMachines/Exceptions/StateMachineDefinitionException.cs index 5641d37b..dffb0696 100644 --- a/Core/Stateflows/StateMachines/Exceptions/StateMachineDefinitionException.cs +++ b/Core/Stateflows/StateMachines/Exceptions/StateMachineDefinitionException.cs @@ -1,9 +1,22 @@ -namespace Stateflows.StateMachines.Exceptions +using System; +using Stateflows.Common.Exceptions; + +namespace Stateflows.StateMachines.Exceptions { #pragma warning disable S3925 // "ISerializable" should be implemented correctly - internal class StateMachineDefinitionException : StateMachineException + internal class StateMachineDefinitionException : BehaviorDefinitionException { - public StateMachineDefinitionException(string message, StateMachineClass stateMachineClass) : base(message, stateMachineClass) { } + public StateMachineClass StateMachineClass { get; } + + public StateMachineDefinitionException(string message, StateMachineClass stateMachineClass) : base(message, stateMachineClass.BehaviorClass) + { + StateMachineClass = stateMachineClass; + } + + public StateMachineDefinitionException(string message, StateMachineClass stateMachineClass, Exception innerException) : base(message, stateMachineClass.BehaviorClass, innerException) + { + StateMachineClass = stateMachineClass; + } } #pragma warning restore S3925 // "ISerializable" should be implemented correctly } diff --git a/Core/Stateflows/StateMachines/Exceptions/StateMachineException.cs b/Core/Stateflows/StateMachines/Exceptions/StateMachineException.cs deleted file mode 100644 index c59cb66c..00000000 --- a/Core/Stateflows/StateMachines/Exceptions/StateMachineException.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Stateflows.Common.Exceptions; - -namespace Stateflows.StateMachines.Exceptions -{ -#pragma warning disable S3925 // "ISerializable" should be implemented correctly - internal class StateMachineException : BehaviorException - { - public StateMachineClass StateMachineClass { get; } - - public StateMachineException(string message, StateMachineClass stateMachineClass) : base(message, stateMachineClass.BehaviorClass) - { - StateMachineClass = stateMachineClass; - } - - public StateMachineException(string message, StateMachineClass stateMachineClass, Exception innerException) : base(message, stateMachineClass.BehaviorClass, innerException) - { - StateMachineClass = stateMachineClass; - } - } -#pragma warning restore S3925 // "ISerializable" should be implemented correctly -} diff --git a/Core/Stateflows/StateMachines/Exceptions/StateMachineRuntimeException.cs b/Core/Stateflows/StateMachines/Exceptions/StateMachineRuntimeException.cs new file mode 100644 index 00000000..31522766 --- /dev/null +++ b/Core/Stateflows/StateMachines/Exceptions/StateMachineRuntimeException.cs @@ -0,0 +1,11 @@ +using Stateflows.Common.Exceptions; + +namespace Stateflows.StateMachines.Exceptions +{ +#pragma warning disable S3925 // "ISerializable" should be implemented correctly + internal class StateMachineRuntimeException : BehaviorRuntimeException + { + public StateMachineRuntimeException(string message, StateMachineClass stateMachineClass) : base(message, stateMachineClass) { } + } +#pragma warning restore S3925 // "ISerializable" should be implemented correctly +} diff --git a/Core/Stateflows/StateMachines/Helpers/StateAction.cs b/Core/Stateflows/StateMachines/Helpers/StateAction.cs index b4c108d0..4e7a6f2c 100644 --- a/Core/Stateflows/StateMachines/Helpers/StateAction.cs +++ b/Core/Stateflows/StateMachines/Helpers/StateAction.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Threading.Tasks; using Stateflows.StateMachines.Context.Interfaces; @@ -6,6 +7,7 @@ namespace Stateflows.StateMachines { public static class StateAction { + [DebuggerHidden] public static Func ToAsync(this Action stateAction) => c => Task.Run(() => stateAction(c)); } diff --git a/Core/Stateflows/StateMachines/Models/Graph.cs b/Core/Stateflows/StateMachines/Models/Graph.cs index a0d01e6a..982c4489 100644 --- a/Core/Stateflows/StateMachines/Models/Graph.cs +++ b/Core/Stateflows/StateMachines/Models/Graph.cs @@ -48,6 +48,17 @@ public Logic Finalize public readonly List ObserverFactories = new List(); + public readonly List RequiredBehaviors = new List(); + + [DebuggerHidden] + public void Validate(IEnumerable behaviorClasses) + { + foreach (var behaviorClass in RequiredBehaviors.Where(bc => !behaviorClasses.Contains(bc))) + { + throw new StateMachineDefinitionException($"{behaviorClass.Type} '{behaviorClass.Name}' required by state machine '{Name}' is not registered", Class); + } + } + [DebuggerHidden] public void Build() { diff --git a/Core/Stateflows/StateMachines/Registration/Builders/StateBuilder.cs b/Core/Stateflows/StateMachines/Registration/Builders/StateBuilder.cs index 10984798..c623c6bb 100644 --- a/Core/Stateflows/StateMachines/Registration/Builders/StateBuilder.cs +++ b/Core/Stateflows/StateMachines/Registration/Builders/StateBuilder.cs @@ -1,12 +1,14 @@ using System; using System.Diagnostics; using System.Threading.Tasks; +using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; using Stateflows.Common; using Stateflows.Common.Exceptions; using Stateflows.Common.Registration; using Stateflows.StateMachines.Events; using Stateflows.StateMachines.Models; +using Stateflows.StateMachines.Extensions; using Stateflows.StateMachines.Exceptions; using Stateflows.StateMachines.Context.Classes; using Stateflows.StateMachines.Context.Interfaces; @@ -14,7 +16,6 @@ using Stateflows.StateMachines.Registration.Interfaces; using Stateflows.StateMachines.Registration.Interfaces.Base; using Stateflows.StateMachines.Registration.Interfaces.Internal; -using Stateflows.StateMachines.Extensions; namespace Stateflows.StateMachines.Registration.Builders { @@ -58,7 +59,7 @@ public IStateBuilder AddOnInitialize(Func actionAsync } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } @@ -96,7 +97,7 @@ public IStateBuilder AddOnFinalize(Func actionAsync) } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } @@ -134,7 +135,7 @@ public IStateBuilder AddOnEntry(Func actionAsync) } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } @@ -172,7 +173,7 @@ public IStateBuilder AddOnExit(Func actionAsync) } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } @@ -427,6 +428,10 @@ public IEmbeddedBehaviorBuilder AddForwardedEvent(ForwardedEventBuildAct : result.Status ); } + else + { + throw new StateDefinitionException(c.SourceState.Name, $"DoActivity '{Vertex.BehaviorName}' not found", c.StateMachine.Id.StateMachineClass); + } }); buildAction?.Invoke(b as IForwardedEventBuilder); diff --git a/Core/Stateflows/StateMachines/Registration/Builders/StateMachineBuilder.cs b/Core/Stateflows/StateMachines/Registration/Builders/StateMachineBuilder.cs index e24b1516..f11dcda4 100644 --- a/Core/Stateflows/StateMachines/Registration/Builders/StateMachineBuilder.cs +++ b/Core/Stateflows/StateMachines/Registration/Builders/StateMachineBuilder.cs @@ -3,17 +3,16 @@ using Microsoft.Extensions.DependencyInjection; using Stateflows.Common; using Stateflows.Common.Models; +using Stateflows.Common.Extensions; using Stateflows.Common.Registration; using Stateflows.StateMachines.Models; using Stateflows.StateMachines.Interfaces; using Stateflows.StateMachines.Exceptions; -using Stateflows.StateMachines.Extensions; using Stateflows.StateMachines.Context.Classes; using Stateflows.StateMachines.Context.Interfaces; using Stateflows.StateMachines.Registration.Interfaces; using Stateflows.StateMachines.Registration.Interfaces.Base; using Stateflows.StateMachines.Registration.Interfaces.Internal; -using Stateflows.Common.Extensions; namespace Stateflows.StateMachines.Registration.Builders { diff --git a/Core/Stateflows/StateMachines/Registration/Builders/TransitionBuilder.cs b/Core/Stateflows/StateMachines/Registration/Builders/TransitionBuilder.cs index fbe38f15..3a5d4d22 100644 --- a/Core/Stateflows/StateMachines/Registration/Builders/TransitionBuilder.cs +++ b/Core/Stateflows/StateMachines/Registration/Builders/TransitionBuilder.cs @@ -51,7 +51,7 @@ public ITransitionBuilder AddGuard(Func, Task } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } @@ -90,7 +90,7 @@ public ITransitionBuilder AddEffect(Func, Tas } catch (Exception e) { - if (e is StateflowsException) + if (e is StateflowsDefinitionException) { throw; } diff --git a/Core/Stateflows/StateMachines/Registration/StateMachinesRegister.cs b/Core/Stateflows/StateMachines/Registration/StateMachinesRegister.cs index 9447b1ea..40103363 100644 --- a/Core/Stateflows/StateMachines/Registration/StateMachinesRegister.cs +++ b/Core/Stateflows/StateMachines/Registration/StateMachinesRegister.cs @@ -3,12 +3,11 @@ using System.Collections.Generic; using System.Runtime.Serialization; using Microsoft.Extensions.DependencyInjection; +using Stateflows.Common.Extensions; using Stateflows.StateMachines.Models; -using Stateflows.StateMachines.Extensions; using Stateflows.StateMachines.Exceptions; using Stateflows.StateMachines.Registration.Builders; using Stateflows.StateMachines.Registration.Interfaces; -using Stateflows.Common.Extensions; namespace Stateflows.StateMachines.Registration { @@ -143,5 +142,14 @@ public void AddGlobalObserver() Services.AddServiceType(); AddGlobalObserver(serviceProvider => serviceProvider.GetRequiredService()); } + + [DebuggerHidden] + public void Validate(IEnumerable behaviorClasses) + { + foreach (var stateMachine in StateMachines.Values) + { + stateMachine.Validate(behaviorClasses); + } + } } } diff --git a/Core/Stateflows/StateMachines/StateMachinesDependencyInjection.cs b/Core/Stateflows/StateMachines/StateMachinesDependencyInjection.cs index 6e8199e6..73d4ec13 100644 --- a/Core/Stateflows/StateMachines/StateMachinesDependencyInjection.cs +++ b/Core/Stateflows/StateMachines/StateMachinesDependencyInjection.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; -using Stateflows.Common; using Stateflows.Common.Interfaces; using Stateflows.Common.Initializer; using Stateflows.Common.Registration.Interfaces; @@ -17,7 +16,7 @@ namespace Stateflows.StateMachines { public static class SystemDependencyInjection { - private readonly static Dictionary Registers = new Dictionary(); + private static readonly Dictionary Registers = new Dictionary(); [DebuggerHidden] public static IStateflowsBuilder AddStateMachines(this IStateflowsBuilder stateflowsBuilder, StateMachinesBuildAction buildAction) @@ -59,21 +58,17 @@ private static StateMachinesRegister EnsureStateMachinesServices(this IStateflow .AddSingleton() .AddSingleton() .AddTransient(provider => - ContextHolder.StateMachineContext.Value ?? + StateMachinesContextHolder.StateMachineContext.Value ?? throw new InvalidOperationException($"No service for type '{typeof(IStateMachineContext).FullName}' is available in this context.") ) .AddTransient(provider => - ContextHolder.StateContext.Value ?? + StateMachinesContextHolder.StateContext.Value ?? throw new InvalidOperationException($"No service for type '{typeof(IStateContext).FullName}' is available in this context.") ) .AddTransient(provider => - ContextHolder.TransitionContext.Value ?? + StateMachinesContextHolder.TransitionContext.Value ?? throw new InvalidOperationException($"No service for type '{typeof(ITransitionContext).FullName}' is available in this context.") ) - .AddTransient(provider => - ContextHolder.ExecutionContext.Value ?? - throw new InvalidOperationException($"No service for type '{typeof(IExecutionContext).FullName}' is available in this context.") - ) ; } diff --git a/Locks/Stateflows.Locks.DistributedLock/DependencyInjection.cs b/Locks/Stateflows.Locks.DistributedLock/DependencyInjection.cs index 93d548ec..73713bf3 100644 --- a/Locks/Stateflows.Locks.DistributedLock/DependencyInjection.cs +++ b/Locks/Stateflows.Locks.DistributedLock/DependencyInjection.cs @@ -16,7 +16,7 @@ public static IStateflowsBuilder AddDistributedLock(this IStateflowsBuilder buil { if (builder.ServiceCollection.IsServiceRegistered()) { - throw new StateflowsException("Another Stateflows lock already registered"); + throw new StateflowsDefinitionException("Another Stateflows lock already registered"); } builder diff --git a/Storage/Stateflows.Storage.EntityFrameworkCore/DependencyInjection.cs b/Storage/Stateflows.Storage.EntityFrameworkCore/DependencyInjection.cs index e2a39904..3db6a302 100644 --- a/Storage/Stateflows.Storage.EntityFrameworkCore/DependencyInjection.cs +++ b/Storage/Stateflows.Storage.EntityFrameworkCore/DependencyInjection.cs @@ -17,7 +17,7 @@ public static IStateflowsBuilder AddEntityFrameworkCoreStorage(this { if (builder.ServiceCollection.IsServiceRegistered()) { - throw new StateflowsException("Another Stateflows storage already registered"); + throw new StateflowsDefinitionException("Another Stateflows storage already registered"); } builder.ServiceCollection diff --git a/Storage/Stateflows.Storage.MongoDb/DependencyInjection.cs b/Storage/Stateflows.Storage.MongoDb/DependencyInjection.cs index ee646aff..7b36a4fd 100644 --- a/Storage/Stateflows.Storage.MongoDb/DependencyInjection.cs +++ b/Storage/Stateflows.Storage.MongoDb/DependencyInjection.cs @@ -16,7 +16,7 @@ public static IStateflowsBuilder AddMongoDBStorage(this IStateflowsBuilder build { if (builder.ServiceCollection.IsServiceRegistered()) { - throw new StateflowsException("Another Stateflows storage already registered"); + throw new StateflowsDefinitionException("Another Stateflows storage already registered"); } builder.ServiceCollection diff --git a/Tests/StateMachine/StateMachine.IntegrationTests/Tests/Typed.cs b/Tests/StateMachine/StateMachine.IntegrationTests/Tests/Typed.cs index 7d017eca..cac14aaf 100644 --- a/Tests/StateMachine/StateMachine.IntegrationTests/Tests/Typed.cs +++ b/Tests/StateMachine/StateMachine.IntegrationTests/Tests/Typed.cs @@ -42,7 +42,9 @@ public async Task TypedStateMachine() { status1 = (await sm.SendAsync(new SomeEvent())).Status; - currentState = (await sm.GetCurrentStateAsync()).Response.StatesStack.First(); + var x = await sm.GetCurrentStateAsync(); + + currentState = (x).Response.StatesStack.First(); status2 = (await sm.SendAsync(new SomeEvent())).Status; }