Reverting wrong commits

This commit is contained in:
lucas.hipolito 2025-10-09 14:36:56 +02:00
parent e22ecf83a0
commit 9ab15d3d15
10 changed files with 92 additions and 130 deletions

View file

@ -0,0 +1,15 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
},
"ElsaServer": {
"Url": "https://localhost:5001/elsa/api"
},
"Hosting": {
"BasePath": ""
}
}

View file

@ -6,34 +6,32 @@ using Elsa.Expressions.JavaScript.TypeDefinitions.Models;
using Elsa.Workflows.Management.Options;
using JetBrains.Annotations;
using Microsoft.Extensions.Options;
namespace Elsa.Expressions.JavaScript.Providers;
/// <summary>
/// Produces <see cref="TypeDefinition"/>s for variable types.
/// </summary>
internal class VariableTypeDefinitionProvider(ITypeDescriber typeDescriber) : TypeDefinitionProvider
[UsedImplicitly]
internal class VariableTypeDefinitionProvider(ITypeDescriber typeDescriber, IOptions<ManagementOptions> options) : TypeDefinitionProvider
{
protected override IEnumerable<TypeDefinition> GetTypeDefinitions(TypeDefinitionContext context)
{
var excludedTypes = new Func<Type, bool>[]
{
type => type == typeof(ExpandoObject),
type => typeof(IDictionary<string, object>).IsAssignableFrom(type),
type => type == typeof(object)
type => type.IsPrimitive,
type => type.ContainsGenericParameters,
type => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IDictionary<,>),
type => type == typeof(object),
type => type == typeof(string)
};
var variables = context.WorkflowGraph.Workflow.Variables;
var variableTypeQuery =
from variable in variables
let variableType = variable.GetVariableType()
where (variableType.IsClass || variableType.IsInterface || variableType.IsEnum) && !variableType.IsPrimitive && !excludedTypes.Any(x => x(variableType))
var variableTypes =
from variableDescriptor in options.Value.VariableDescriptors
let variableType = variableDescriptor.Type
where (variableType.IsClass || variableType.IsInterface || variableType.IsEnum) && !excludedTypes.Any(x => x(variableType))
select variableType;
var variableTypes = variableTypeQuery.Distinct();
foreach (var variableType in variableTypes)
foreach (var variableType in variableTypes.Distinct())
{
yield return typeDescriber.DescribeType(variableType);
}

View file

@ -1,9 +1,7 @@
using System.Text;
using Elsa.Expressions.JavaScript.TypeDefinitions.Contracts;
using Elsa.Expressions.JavaScript.TypeDefinitions.Models;
namespace Elsa.Expressions.JavaScript.TypeDefinitions.Services;
/// <inheritdoc />
public class TypeDefinitionDocumentRenderer : ITypeDefinitionDocumentRenderer
{
@ -11,19 +9,14 @@ public class TypeDefinitionDocumentRenderer : ITypeDefinitionDocumentRenderer
public string Render(TypeDefinitionsDocument document)
{
var stringBuilder = new StringBuilder();
foreach (var functionDefinition in document.Functions)
Render(functionDefinition, stringBuilder);
foreach (var typeDefinition in document.Types)
Render(typeDefinition, stringBuilder);
foreach (var variableDefinition in document.Variables)
Render(variableDefinition, stringBuilder);
return stringBuilder.ToString();
}
private void Render(FunctionDefinition functionDefinition, StringBuilder output)
{
var returnType = functionDefinition.ReturnType != null ? $": {functionDefinition.ReturnType}" : "";
@ -35,11 +28,9 @@ public class TypeDefinitionDocumentRenderer : ITypeDefinitionDocumentRenderer
var returnType = functionDefinition.ReturnType != null ? $" => {functionDefinition.ReturnType}" : "";
output.AppendLine($"{functionDefinition.Name}: ({RenderParameters(functionDefinition.Parameters)}){returnType};");
}
private void Render(TypeDefinition typeDefinition, StringBuilder output)
{
output.AppendLine($"declare {typeDefinition.DeclarationKeyword} {typeDefinition.Name} {{");
if (typeDefinition.DeclarationKeyword == "enum")
{
foreach (var property in typeDefinition.Properties)
@ -50,15 +41,13 @@ public class TypeDefinitionDocumentRenderer : ITypeDefinitionDocumentRenderer
foreach (var property in typeDefinition.Properties)
Render(property, output);
}
foreach (var method in typeDefinition.Methods)
RenderMethod(method, output);
output.AppendLine("}");
}
private void Render(PropertyDefinition property, StringBuilder output) => output.AppendLine($"{property.Name}{(property.IsOptional ? "?" : "")}: {property.Type};");
private void RenderEnumMember(PropertyDefinition property, StringBuilder output) => output.AppendLine($"{property.Name} = \"{property.Name}\";");
private void RenderEnumMember(PropertyDefinition property, StringBuilder output) => output.AppendLine($"{property.Name} = \"{property.Name}\",");
private void Render(VariableDefinition variable, StringBuilder output) => output.AppendLine($"declare var {variable.Name}: {variable.Type};");
string RenderParameter(ParameterDefinition parameter) => $"{parameter.Name}{(parameter.IsOptional ? "?" : "")}: {parameter.Type}";
string RenderParameters(IEnumerable<ParameterDefinition> parameters) => string.Join(", ", parameters.Select(RenderParameter));

View file

@ -1,17 +1,15 @@
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using Elsa.Extensions;
using Elsa.Expressions.JavaScript.Contracts;
using Elsa.Expressions.JavaScript.TypeDefinitions.Contracts;
using Elsa.Expressions.JavaScript.TypeDefinitions.Models;
namespace Elsa.Expressions.JavaScript.TypeDefinitions.Services;
/// <inheritdoc />
public class TypeDescriber : ITypeDescriber
{
private readonly ITypeAliasRegistry _typeAliasRegistry;
/// <summary>
/// Constructor.
/// </summary>
@ -30,17 +28,18 @@ public class TypeDescriber : ITypeDescriber
Properties = GetPropertyDefinitions(type).DistinctBy(x => x.Name).ToList(),
Methods = GetMethodDefinitions(type).DistinctBy(x => x.Name).ToList()
};
return typeDefinition;
}
private IEnumerable<FunctionDefinition> GetMethodDefinitions(Type type)
{
if(type.IsEnum)
yield break;
#pragma warning disable IL2070
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static).Where(x => !x.IsSpecialName).ToList();
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
.Where(x => !x.IsSpecialName)
.Where(x => x.GetCustomAttribute<CompilerGeneratedAttribute>() == null)
.ToList();
#pragma warning restore IL2070
foreach (var method in methods)
@ -53,11 +52,9 @@ public class TypeDescriber : ITypeDescriber
};
}
}
private IEnumerable<ParameterDefinition> GetMethodParameters(MethodInfo method)
{
var parameters = method.GetParameters();
foreach (var parameter in parameters)
{
yield return new ParameterDefinition
@ -68,7 +65,6 @@ public class TypeDescriber : ITypeDescriber
};
}
}
private IEnumerable<PropertyDefinition> GetPropertyDefinitions([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] Type type)
{
// If the type is an enum, enumerate its members.
@ -83,12 +79,10 @@ public class TypeDescriber : ITypeDescriber
IsOptional = false,
};
}
yield break;
}
var properties = type.GetProperties();
foreach (var property in properties)
{
yield return new PropertyDefinition
@ -99,7 +93,6 @@ public class TypeDescriber : ITypeDescriber
};
}
}
private static string GetDeclarationKeyword(Type type) =>
type switch
{

View file

@ -1,9 +1,7 @@
using System.Runtime.CompilerServices;
using Elsa.Workflows;
using Elsa.Workflows.Attributes;
namespace Elsa.Http;
/// <summary>
/// Send an HTTP request.
/// </summary>
@ -14,7 +12,6 @@ public class SendHttpRequest : SendHttpRequestBase
public SendHttpRequest([CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : base(source, line)
{
}
/// <summary>
/// A list of expected status codes to handle and the corresponding activity to execute when the status code matches.
/// </summary>
@ -23,21 +20,21 @@ public class SendHttpRequest : SendHttpRequestBase
UIHint = "http-status-codes"
)]
public ICollection<HttpStatusCodeCase> ExpectedStatusCodes { get; set; } = new List<HttpStatusCodeCase>();
/// <summary>
/// The activity to execute when the HTTP status code does not match any of the expected status codes.
/// </summary>
[Port]
public IActivity? UnmatchedStatusCode { get; set; }
/// <summary>
/// The activity to execute when the HTTP request fails to connect.
/// </summary>
[Port]
public IActivity? FailedToConnect { get; set; }
/// <summary>
/// The activity to execute when the HTTP request times out.
/// </summary>
[Port]
public IActivity? Timeout { get; set; }
/// <inheritdoc />
@ -47,22 +44,18 @@ public class SendHttpRequest : SendHttpRequestBase
var statusCode = (int)response.StatusCode;
var matchingCase = expectedStatusCodes.FirstOrDefault(x => x.StatusCode == statusCode);
var activity = matchingCase != null ? matchingCase.Activity : UnmatchedStatusCode;
await context.ScheduleActivityAsync(activity, OnChildActivityCompletedAsync);
}
/// <inheritdoc />
protected override async ValueTask HandleRequestExceptionAsync(ActivityExecutionContext context, HttpRequestException exception)
{
await context.ScheduleActivityAsync(FailedToConnect, OnChildActivityCompletedAsync);
}
/// <inheritdoc />
protected override async ValueTask HandleTaskCanceledExceptionAsync(ActivityExecutionContext context, TaskCanceledException exception)
{
await context.ScheduleActivityAsync(Timeout, OnChildActivityCompletedAsync);
}
private async ValueTask OnChildActivityCompletedAsync(ActivityCompletedContext context)
{
await context.TargetContext.CompleteActivityAsync();

View file

@ -26,9 +26,7 @@ using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
namespace Elsa.Http.Features;
/// <summary>
/// Installs services related to HTTP services and activities.
/// </summary>
@ -38,32 +36,26 @@ public class HttpFeature(IModule module) : FeatureBase(module)
{
private Func<IServiceProvider, IHttpEndpointRoutesProvider> _httpEndpointRouteProvider = sp => sp.GetRequiredService<DefaultHttpEndpointRoutesProvider>();
private Func<IServiceProvider, IHttpEndpointBasePathProvider> _httpEndpointBasePathProvider = sp => sp.GetRequiredService<DefaultHttpEndpointBasePathProvider>();
/// <summary>
/// A delegate to configure <see cref="HttpActivityOptions"/>.
/// </summary>
public Action<HttpActivityOptions>? ConfigureHttpOptions { get; set; }
/// <summary>
/// A delegate to configure <see cref="HttpFileCacheOptions"/>.
/// </summary>
public Action<HttpFileCacheOptions>? ConfigureHttpFileCacheOptions { get; set; }
/// <summary>
/// A delegate that is invoked when authorizing an inbound HTTP request.
/// </summary>
public Func<IServiceProvider, IHttpEndpointAuthorizationHandler> HttpEndpointAuthorizationHandler { get; set; } = sp => sp.GetRequiredService<AuthenticationBasedHttpEndpointAuthorizationHandler>();
/// <summary>
/// A delegate that is invoked when an HTTP workflow faults.
/// </summary>
public Func<IServiceProvider, IHttpEndpointFaultHandler> HttpEndpointWorkflowFaultHandler { get; set; } = sp => sp.GetRequiredService<DefaultHttpEndpointFaultHandler>();
/// <summary>
/// A delegate to configure the <see cref="IContentTypeProvider"/>.
/// </summary>
public Func<IServiceProvider, IContentTypeProvider> ContentTypeProvider { get; set; } = _ => new FileExtensionContentTypeProvider();
/// <summary>
/// A delegate to configure the <see cref="IFileCacheStorageProvider"/>.
/// </summary>
@ -75,7 +67,7 @@ public class HttpFeature(IModule module) : FeatureBase(module)
};
/// <summary>
/// A delegate to configure the <see cref="HttpClient"/> used when by the <see cref="FlowSendHttpRequest"/> activity.
/// A delegate to configure the <see cref="HttpClient"/> used when by the <see cref="FlowSendHttpRequest"/> and <see cref="SendHttpRequest"/> activities.
/// </summary>
public Action<IServiceProvider, HttpClient> HttpClient { get; set; } = (_, _) => { };
@ -83,7 +75,6 @@ public class HttpFeature(IModule module) : FeatureBase(module)
/// A delegate to configure the <see cref="HttpClientBuilder"/> for <see cref="HttpClient"/>.
/// </summary>
public Action<IHttpClientBuilder> HttpClientBuilder { get; set; } = _ => { };
/// <summary>
/// A list of <see cref="IHttpCorrelationIdSelector"/> types to register with the service collection.
/// </summary>
@ -92,7 +83,6 @@ public class HttpFeature(IModule module) : FeatureBase(module)
typeof(HeaderHttpCorrelationIdSelector),
typeof(QueryStringHttpCorrelationIdSelector)
};
/// <summary>
/// A list of <see cref="IHttpWorkflowInstanceIdSelector"/> types to register with the service collection.
/// </summary>
@ -101,12 +91,10 @@ public class HttpFeature(IModule module) : FeatureBase(module)
typeof(HeaderHttpWorkflowInstanceIdSelector),
typeof(QueryStringHttpWorkflowInstanceIdSelector)
};
public HttpFeature WithHttpEndpointRoutesProvider<T>() where T : IHttpEndpointRoutesProvider
{
return WithHttpEndpointRoutesProvider(sp => sp.GetRequiredService<T>());
}
public HttpFeature WithHttpEndpointRoutesProvider(Func<IServiceProvider, IHttpEndpointRoutesProvider> httpEndpointRouteProvider)
{
_httpEndpointRouteProvider = httpEndpointRouteProvider;
@ -124,7 +112,6 @@ public class HttpFeature(IModule module) : FeatureBase(module)
_httpEndpointBasePathProvider = httpEndpointBasePathProvider;
return this;
}
/// <inheritdoc />
public override void Configure()
{
@ -140,13 +127,10 @@ public class HttpFeature(IModule module) : FeatureBase(module)
typeof(HttpFile),
typeof(Downloadable)
], "HTTP");
management.AddActivitiesFrom<HttpFeature>();
});
Module.UseResilience(resilience => resilience.AddResilienceStrategyType<HttpResilienceStrategy>());
}
/// <inheritdoc />
public override void Apply()
{
@ -155,15 +139,11 @@ public class HttpFeature(IModule module) : FeatureBase(module)
options.BasePath = "/workflows";
options.BaseUrl = new Uri("http://localhost");
});
var configureFileCacheOptions = ConfigureHttpFileCacheOptions ?? (options => { options.TimeToLive = TimeSpan.FromDays(7); });
Services.Configure(configureOptions);
Services.Configure(configureFileCacheOptions);
var httpClientBuilder = Services.AddHttpClient<SendHttpRequestBase>(HttpClient);
HttpClientBuilder(httpClientBuilder);
Services
.AddScoped<IRouteMatcher, RouteMatcher>()
.AddScoped<IRouteTable, RouteTable>()
@ -172,31 +152,25 @@ public class HttpFeature(IModule module) : FeatureBase(module)
.AddScoped<IHttpWorkflowLookupService, HttpWorkflowLookupService>()
.AddScoped(ContentTypeProvider)
.AddHttpContextAccessor()
// Handlers.
.AddNotificationHandler<UpdateRouteTable>()
// Content parsers.
.AddSingleton<IHttpContentParser, JsonHttpContentParser>()
.AddSingleton<IHttpContentParser, XmlHttpContentParser>()
.AddSingleton<IHttpContentParser, PlainTextHttpContentParser>()
.AddSingleton<IHttpContentParser, TextHtmlHttpContentParser>()
.AddSingleton<IHttpContentParser, FileHttpContentParser>()
// HTTP content factories.
.AddScoped<IHttpContentFactory, TextContentFactory>()
.AddScoped<IHttpContentFactory, JsonContentFactory>()
.AddScoped<IHttpContentFactory, XmlContentFactory>()
.AddScoped<IHttpContentFactory, FormUrlEncodedHttpContentFactory>()
// Activity property options providers.
.AddScoped<IPropertyUIHandler, HttpContentTypeOptionsProvider>()
.AddScoped<IPropertyUIHandler, HttpEndpointPathUIHandler>()
.AddScoped(_httpEndpointBasePathProvider)
// Port resolvers.
.AddScoped<IActivityResolver, SendHttpRequestActivityResolver>()
// HTTP endpoint handlers.
.AddScoped<AuthenticationBasedHttpEndpointAuthorizationHandler>()
.AddScoped<AllowAnonymousHttpEndpointAuthorizationHandler>()
@ -209,7 +183,6 @@ public class HttpFeature(IModule module) : FeatureBase(module)
// Startup tasks.
.AddStartupTask<UpdateRouteTableStartupTask>()
// Downloadable content handlers.
.AddScoped<IDownloadableManager, DefaultDownloadableManager>()
.AddScoped<IDownloadableContentHandler, MultiDownloadableContentHandler>()
@ -220,28 +193,21 @@ public class HttpFeature(IModule module) : FeatureBase(module)
.AddScoped<IDownloadableContentHandler, UrlDownloadableContentHandler>()
.AddScoped<IDownloadableContentHandler, StringDownloadableContentHandler>()
.AddScoped<IDownloadableContentHandler, HttpFileDownloadableContentHandler>()
//Trigger payload validators.
.AddTriggerPayloadValidator<HttpEndpointTriggerPayloadValidator, HttpEndpointBookmarkPayload>()
// File caches.
.AddScoped(FileCache)
.AddScoped<ZipManager>()
// AuthenticationBasedHttpEndpointAuthorizationHandler requires Authorization services.
// We could consider creating a separate module for installing authorization services.
.AddAuthorization();
// HTTP clients.
Services.AddHttpClient<IFileDownloader, HttpClientFileDownloader>();
// Add selectors.
foreach (var httpCorrelationIdSelectorType in HttpCorrelationIdSelectorTypes)
Services.AddScoped(typeof(IHttpCorrelationIdSelector), httpCorrelationIdSelectorType);
foreach (var httpWorkflowInstanceIdSelectorType in HttpWorkflowInstanceIdSelectorTypes)
Services.AddScoped(typeof(IHttpWorkflowInstanceIdSelector), httpWorkflowInstanceIdSelectorType);
Services.Configure<ExpressionOptions>(options =>
{
options.AddTypeAlias<HttpRequest>("HttpRequest");

View file

@ -1,8 +1,6 @@
using Elsa.Workflows;
using Elsa.Workflows.Models;
namespace Elsa.Http.PortResolvers;
/// <summary>
/// Returns a list of outbound activities for a given <see cref="SendHttpRequest"/> activity's expected status codes.
/// </summary>
@ -10,32 +8,25 @@ public class SendHttpRequestActivityResolver : IActivityResolver
{
/// <inheritdoc />
public int Priority => 0;
/// <inheritdoc />
public bool GetSupportsActivity(IActivity activity) => activity is SendHttpRequest;
/// <inheritdoc />
public ValueTask<IEnumerable<ActivityPort>> GetActivityPortsAsync(IActivity activity, CancellationToken cancellationToken = default)
{
IEnumerable<ActivityPort> ports = GetPortsInternal(activity);
return new ValueTask<IEnumerable<ActivityPort>>(ports);
var ports = GetPortsInternal(activity);
return new(ports);
}
private IEnumerable<ActivityPort> GetPortsInternal(IActivity activity)
{
var sendHttpRequest = (SendHttpRequest)activity;
var cases = sendHttpRequest.ExpectedStatusCodes.Where(x => x.Activity != null);
foreach (var @case in cases)
yield return ActivityPort.FromActivity(@case.Activity!, @case.StatusCode.ToString());
if (sendHttpRequest.Timeout != null)
yield return ActivityPort.FromActivity(sendHttpRequest.Timeout, nameof(SendHttpRequest.Timeout));
if (sendHttpRequest.FailedToConnect != null)
yield return ActivityPort.FromActivity(sendHttpRequest.FailedToConnect, nameof(SendHttpRequest.FailedToConnect));
if (sendHttpRequest.UnmatchedStatusCode != null)
yield return ActivityPort.FromActivity(sendHttpRequest.UnmatchedStatusCode, nameof(SendHttpRequest.UnmatchedStatusCode));
}

View file

@ -4,14 +4,12 @@ using Elsa.Workflows.Runtime;
using FastEndpoints;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Http;
namespace Elsa.Workflows.Api.Endpoints.Bookmarks.Resume;
/// <summary>
/// Resumes a bookmarked workflow instance with the bookmark ID specified in the provided SAS token.
/// </summary>
[PublicAPI]
internal class Resume(ITokenService tokenService, IBookmarkQueue bookmarkQueue, IPayloadSerializer serializer) : ElsaEndpoint<Request>
internal class Resume(ITokenService tokenService, IWorkflowResumer workflowResumer, IBookmarkQueue bookmarkQueue, IPayloadSerializer serializer) : ElsaEndpoint<Request>
{
/// <inheritdoc />
public override void Configure()
@ -20,25 +18,27 @@ internal class Resume(ITokenService tokenService, IBookmarkQueue bookmarkQueue,
Verbs(Http.GET, Http.POST);
AllowAnonymous();
}
/// <inheritdoc />
public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
{
var token = Query<string>("t")!;
var asynchronous = Query<bool>("async", false);
if (!tokenService.TryDecryptToken<BookmarkTokenPayload>(token, out var payload))
AddError("Invalid token.");
var input = HttpContext.Request.Method == HttpMethods.Post ? request.Input : GetInputFromQueryString();
if (ValidationFailed)
{
await Send.ErrorsAsync(cancellation: cancellationToken);
return;
}
await ResumeBookmarkedWorkflowAsync(payload, input, cancellationToken);
// Some clients, like Blazor, may prematurely cancel their request upon navigation away from the page.
// In this case, we don't want to cancel the workflow execution.
// We need to better understand the conditions that cause this.
var workflowCancellationToken = CancellationToken.None;
await ResumeBookmarkedWorkflowAsync(payload, input, asynchronous, workflowCancellationToken);
if (!HttpContext.Response.HasStarted)
await Send.OkAsync(cancellationToken);
}
@ -48,7 +48,6 @@ internal class Resume(ITokenService tokenService, IBookmarkQueue bookmarkQueue,
var inputJson = Query<string?>("in", false);
if (string.IsNullOrWhiteSpace(inputJson))
return null;
try
{
return serializer.Deserialize<IDictionary<string, object>>(inputJson);
@ -59,21 +58,36 @@ internal class Resume(ITokenService tokenService, IBookmarkQueue bookmarkQueue,
return null;
}
}
private async Task ResumeBookmarkedWorkflowAsync(BookmarkTokenPayload tokenPayload, IDictionary<string, object>? input, CancellationToken cancellationToken)
private async Task ResumeBookmarkedWorkflowAsync(BookmarkTokenPayload tokenPayload, IDictionary<string, object>? input, bool asynchronous, CancellationToken cancellationToken)
{
var bookmarkId = tokenPayload.BookmarkId;
var workflowInstanceId = tokenPayload.WorkflowInstanceId;
var item = new NewBookmarkQueueItem
if (asynchronous)
{
var item = new NewBookmarkQueueItem
{
BookmarkId = bookmarkId,
WorkflowInstanceId = workflowInstanceId,
Options = new()
{
Input = input
}
};
await bookmarkQueue.EnqueueAsync(item, cancellationToken);
return;
}
var resumeRequest = new ResumeBookmarkRequest
{
BookmarkId = bookmarkId,
WorkflowInstanceId = workflowInstanceId,
Options = new()
{
Input = input
}
Input = input
};
await bookmarkQueue.EnqueueAsync(item, cancellationToken);
await workflowResumer.ResumeAsync(resumeRequest, cancellationToken);
}
}

View file

@ -0,0 +1,6 @@
namespace Elsa.Workflows.Exceptions;
public class InputEvaluationException(string inputName, string message, Exception exception) : Exception(message, exception)
{
public string InputName { get; } = inputName;
}

View file

@ -3,11 +3,11 @@ using Elsa.Expressions.Contracts;
using Elsa.Expressions.Helpers;
using Elsa.Expressions.Models;
using Elsa.Workflows;
using Elsa.Workflows.Exceptions;
using Elsa.Workflows.Models;
// ReSharper disable once CheckNamespace
namespace Elsa.Extensions;
public static partial class ActivityExecutionContextExtensions
{
/// <summary>
@ -17,14 +17,11 @@ public static partial class ActivityExecutionContextExtensions
{
var activityDescriptor = context.ActivityDescriptor;
var inputDescriptors = activityDescriptor.Inputs.Where(x => x.AutoEvaluate).ToList();
// Evaluate inputs.
foreach (var inputDescriptor in inputDescriptors)
await EvaluateInputPropertyAsync(context, activityDescriptor, inputDescriptor);
context.SetHasEvaluatedProperties();
}
/// <summary>
/// Evaluates the specified input property of the activity.
/// </summary>
@ -34,7 +31,6 @@ public static partial class ActivityExecutionContextExtensions
var input = await EvaluateInputPropertyAsync(context, inputName);
return input.ConvertTo<T>();
}
/// <summary>
/// Evaluates a specific input property of the activity.
/// </summary>
@ -44,13 +40,10 @@ public static partial class ActivityExecutionContextExtensions
var activityRegistryLookup = context.GetRequiredService<IActivityRegistryLookupService>();
var activityDescriptor = await activityRegistryLookup.FindAsync(activity.Type) ?? throw new Exception("Activity descriptor not found");
var inputDescriptor = activityDescriptor.GetWrappedInputPropertyDescriptor(activity, inputName);
if (inputDescriptor == null)
throw new Exception($"No input with name {inputName} could be found");
return await EvaluateInputPropertyAsync(context, activityDescriptor, inputDescriptor);
}
/// <summary>
/// Evaluates the specified input and sets the result in the activity execution context's memory space.
/// </summary>
@ -66,19 +59,29 @@ public static partial class ActivityExecutionContextExtensions
memoryBlockReference.Set(context, value);
return value;
}
private static async Task<object?> EvaluateInputPropertyAsync(this ActivityExecutionContext context, ActivityDescriptor activityDescriptor, InputDescriptor inputDescriptor)
{
try
{
return await EvaluateInputPropertyCoreAsync(context, activityDescriptor, inputDescriptor);
}
catch (Exception e)
{
throw new InputEvaluationException(inputDescriptor.Name, $"Failed to evaluate activity input '{inputDescriptor.Name}'", e);
}
}
private static async Task<object?> EvaluateInputPropertyCoreAsync(this ActivityExecutionContext context, ActivityDescriptor activityDescriptor, InputDescriptor inputDescriptor)
{
var activity = context.Activity;
var defaultValue = inputDescriptor.DefaultValue;
var value = defaultValue;
var input = inputDescriptor.ValueGetter(activity);
var identityGenerator = context.GetRequiredService<IIdentityGenerator>();
if (inputDescriptor.IsWrapped)
{
var wrappedInput = (Input?)input;
if (defaultValue != null && wrappedInput == null)
{
var typedInput = typeof(Input<>).MakeGenericType(inputDescriptor.Type);
@ -94,7 +97,6 @@ public static partial class ActivityExecutionContextExtensions
var expressionEvaluator = context.GetRequiredService<IExpressionEvaluator>();
var expressionExecutionContext = context.ExpressionExecutionContext;
var inputEvaluatorType = inputDescriptor.EvaluatorType ?? typeof(DefaultActivityInputEvaluator);
if (wrappedInput?.Expression != null)
{
var inputEvaluator = (IActivityInputEvaluator)context.GetRequiredService(inputEvaluatorType);
@ -102,9 +104,7 @@ public static partial class ActivityExecutionContextExtensions
value = await inputEvaluator.EvaluateAsync(inputEvaluatorContext);
}
}
var memoryReference = wrappedInput?.MemoryBlockReference();
if (memoryReference != null)
{
// When input is created from an activity provider, there may be no memory block reference ID.
@ -119,9 +119,7 @@ public static partial class ActivityExecutionContextExtensions
{
value = input;
}
await StoreInputValueAsync(context, inputDescriptor, value!);
return value;
}
@ -138,7 +136,6 @@ public static partial class ActivityExecutionContextExtensions
// var filterResult = await manager.RunFiltersAsync(filterContext);
context.ActivityState[inputDescriptor.Name] = value;
}
return Task.CompletedTask;
}
}