public async Task RunAsync( ITransitionCarrier transitionCarrier, ITransitionData transitionData, CancellationToken ct) { var transitionDescriptor = await transitionData.GetTransitionDescriptorAsync(ct); if (transitionDescriptor.Type == TransitionType.InvokeRoutine || transitionDescriptor.Type == TransitionType.ContinueRoutine) { await RunRoutineAsync(transitionCarrier, transitionData, transitionDescriptor, ct); } else { throw new InvalidOperationException(); } }
/// <inheritdoc /> public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { ITransitionData currentValue = (ITransitionData)value; if (currentValue == null) { return; } writer.WriteStartObject(); { writer.WritePropertyName("Target"); writer.WriteValue((IStep)null); writer.WritePropertyName("Conditions"); serializer.Serialize(writer, currentValue.Conditions); } writer.WriteEndObject(); }
private async Task RunRoutineAsync( ITransitionCarrier transitionCarrier, ITransitionData transitionData, TransitionDescriptor transitionDescriptor, CancellationToken ct) { using (_transitionScope.Enter(transitionDescriptor)) { var transitionMonitor = _transitionScope.CurrentMonitor; var serviceId = await transitionData.GetServiceIdAsync(ct); var routineDescriptor = await transitionData.GetRoutineDescriptorAsync(ct); var serviceInstance = #warning IntrinsicRoutines must be registered in the service registry, but it needs the engine IoC to resolve. serviceId.ProxyName == nameof(IntrinsicRoutines) ? _intrinsicRoutines : _serviceProxyBuilder.Build(serviceId); #warning check if the serviceInstance proxy is an actual non-abstract class with implementation // Need exact underlying type of the service implementation type to call // the routine method directly without using the virtual method table. var serviceType = (serviceInstance as IProxy)?.ObjectType ?? serviceInstance.GetType(); var routineMethod = _routineMethodResolver.Resolve(serviceType, routineDescriptor.MethodId); var serviceStateContainer = _serviceStateValueContainerProvider.CreateContainer(serviceInstance); var isStatefullService = serviceStateContainer.GetCount() > 0; if (isStatefullService) { await transitionData.ReadServiceStateAsync(serviceStateContainer, ct); } Task completionTask; IValueContainer asmValueContainer = null; if (TryCreateAsyncStateMachine(routineMethod, out var asmInstance, out var asmMetadata, out completionTask)) { var isContinuation = transitionDescriptor.Type == TransitionType.ContinueRoutine; asmValueContainer = await LoadRoutineStateAsync(transitionData, asmInstance, asmMetadata, isContinuation, ct); asmMetadata.Owner.FieldInfo?.SetValue(asmInstance, serviceInstance); transitionMonitor.OnRoutineStart( serviceId, routineDescriptor, serviceInstance, routineMethod, asmInstance); try { #warning possibly need to create a proxy? on a sealed ASM class? How to capture Task.Delay if it's not immediate after first MoveNext? asmInstance.MoveNext(); } catch (Exception ex) { // The MoveNext() must not throw, but instead complete the task with an error. // try-catch is added just in case for a non-compiler-generated state machine. var taskResultType = TaskAccessor.GetTaskResultType(routineMethod.ReturnType); completionTask = TaskAccessor.FromException(taskResultType, ex); } }