Type name imrovements
This commit is contained in:
parent
556ab9c26c
commit
0729cb2762
|
|
@ -30,16 +30,15 @@ public static class ActivityExtensions
|
|||
return (Input?)inputProp.GetValue(activity);
|
||||
}
|
||||
|
||||
public static IEnumerable<Output> GetOutputs(this IActivity activity)
|
||||
public static IEnumerable<NamedOutput> GetOutputs(this IActivity activity)
|
||||
{
|
||||
var outputProps = activity.GetType().GetProperties().Where(x => typeof(Output).IsAssignableFrom(x.PropertyType)).ToList();
|
||||
|
||||
var query =
|
||||
from outputProp in outputProps
|
||||
select (Output?)outputProp.GetValue(activity)
|
||||
into output
|
||||
let output = (Output?)outputProp.GetValue(activity)
|
||||
where output != null
|
||||
select output;
|
||||
select new NamedOutput(outputProp.Name, output);
|
||||
|
||||
return query.Select(x => x!).ToList();
|
||||
}
|
||||
|
|
|
|||
22
src/core/Elsa.Core/Extensions/TypeExtensions.cs
Normal file
22
src/core/Elsa.Core/Extensions/TypeExtensions.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using System.Collections.Concurrent;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Elsa;
|
||||
|
||||
public static class TypeExtensions
|
||||
{
|
||||
private static readonly ConcurrentDictionary<Type, string> SimpleAssemblyQualifiedTypeNameCache = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the assembly-qualified name of the type, without any version info etc.
|
||||
/// E.g. "System.String, System.Private.CoreLib"
|
||||
/// </summary>
|
||||
public static string GetSimpleAssemblyQualifiedName(this Type type)
|
||||
{
|
||||
if (type == null) throw new ArgumentNullException(nameof(type));
|
||||
|
||||
return SimpleAssemblyQualifiedTypeNameCache.GetOrAdd(type, GetSimpleAssemblyQualifiedNameInternal);
|
||||
}
|
||||
|
||||
private static string GetSimpleAssemblyQualifiedNameInternal(Type type) => $"{type.FullName}, {Assembly.GetAssembly(type)!.GetName().Name}";
|
||||
}
|
||||
38
src/core/Elsa.Core/Helpers/ActivityTypeNameHelper.cs
Normal file
38
src/core/Elsa.Core/Helpers/ActivityTypeNameHelper.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
using System.Reflection;
|
||||
using Elsa.Attributes;
|
||||
|
||||
namespace Elsa.Helpers;
|
||||
|
||||
public static class ActivityTypeNameHelper
|
||||
{
|
||||
public static string? GenerateNamespace(Type activityType)
|
||||
{
|
||||
var activityAttr = activityType.GetCustomAttribute<ActivityAttribute>();
|
||||
return activityAttr?.Namespace ?? activityType.Namespace;
|
||||
}
|
||||
|
||||
public static string GenerateTypeName(Type type, string? ns)
|
||||
{
|
||||
var activityAttr = type.GetCustomAttribute<ActivityAttribute>();
|
||||
var typeName = activityAttr?.TypeName ?? type.Name;
|
||||
return ns != null ? $"{ns}.{typeName}" : typeName;
|
||||
}
|
||||
|
||||
public static string GenerateTypeName<T>() => GenerateTypeName(typeof(T));
|
||||
|
||||
public static string GenerateTypeName(Type type)
|
||||
{
|
||||
var ns = GenerateNamespace(type);
|
||||
return GenerateTypeName(type, ns);
|
||||
}
|
||||
|
||||
public static string? GetCategoryFromNamespace(string? ns)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ns))
|
||||
return null;
|
||||
|
||||
var index = ns.LastIndexOf('.');
|
||||
|
||||
return index < 0 ? ns : ns[(index + 1)..];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +1,7 @@
|
|||
using System.Reflection;
|
||||
using Elsa.Attributes;
|
||||
|
||||
namespace Elsa.Helpers;
|
||||
|
||||
public static class TypeNameHelper
|
||||
{
|
||||
public static string? GenerateNamespace(Type activityType)
|
||||
{
|
||||
var activityAttr = activityType.GetCustomAttribute<ActivityAttribute>();
|
||||
return activityAttr?.Namespace ?? activityType.Namespace;
|
||||
}
|
||||
|
||||
public static string GenerateTypeName(Type type, string? ns)
|
||||
{
|
||||
var activityAttr = type.GetCustomAttribute<ActivityAttribute>();
|
||||
var typeName = activityAttr?.TypeName ?? type.Name;
|
||||
return ns != null ? $"{ns}.{typeName}" : typeName;
|
||||
}
|
||||
|
||||
public static string GenerateTypeName<T>() => GenerateTypeName(typeof(T));
|
||||
|
||||
public static string GenerateTypeName(Type type)
|
||||
{
|
||||
var ns = GenerateNamespace(type);
|
||||
return GenerateTypeName(type, ns);
|
||||
}
|
||||
|
||||
public static string? GetCategoryFromNamespace(string? ns)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ns))
|
||||
return null;
|
||||
|
||||
var index = ns.LastIndexOf('.');
|
||||
|
||||
return index < 0 ? ns : ns[(index + 1)..];
|
||||
}
|
||||
public static string GenerateTypeName(Type type) => type.FullName!;
|
||||
}
|
||||
|
|
@ -47,11 +47,11 @@ public class IdentityGraphService : IIdentityGraphService
|
|||
|
||||
seed = 0;
|
||||
var outputs = activity.GetOutputs();
|
||||
var assignedOutputs = outputs.Where(x => x.LocationReference != null! && x.LocationReference.Id == null!).ToList();
|
||||
var assignedOutputs = outputs.Where(x => x.Value.LocationReference != null! && x.Value.LocationReference.Id == null!).ToList();
|
||||
|
||||
foreach (var output in assignedOutputs)
|
||||
{
|
||||
var locationReference = output.LocationReference;
|
||||
var locationReference = output.Value.LocationReference;
|
||||
locationReference.Id = $"{activity.Id}:output-{++seed}";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ public class WorkflowStateSerializer : IWorkflowStateSerializer
|
|||
{
|
||||
var cancellationToken = workflowExecutionContext.CancellationToken;
|
||||
var activity = workflowExecutionContext.FindActivityById(activityExecutionContextState.ScheduledActivityId);
|
||||
var register = new Register(activityExecutionContextState.Register.Locations);
|
||||
var register = workflowExecutionContext.Register;
|
||||
var workflow = workflowExecutionContext.Workflow;
|
||||
var expressionInput = workflowExecutionContext.Input;
|
||||
var expressionExecutionContext = new ExpressionExecutionContext(_serviceProvider, register, workflow, expressionInput, workflowExecutionContext.TransientProperties, default, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ public abstract class Activity : IActivity, ISignalHandler
|
|||
|
||||
protected Activity()
|
||||
{
|
||||
TypeName = TypeNameHelper.GenerateTypeName(GetType());
|
||||
TypeName = ActivityTypeNameHelper.GenerateTypeName(GetType());
|
||||
Behaviors.Add<ScheduledChildCallbackBehavior>();
|
||||
Behaviors.Add<AutoCompleteBehavior>();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ public class ExpressionExecutionContext
|
|||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ExpressionExecutionContext(IServiceProvider serviceProvider,
|
||||
public ExpressionExecutionContext(
|
||||
IServiceProvider serviceProvider,
|
||||
Register register,
|
||||
Workflow workflow,
|
||||
IDictionary<string, object> input,
|
||||
|
|
@ -23,7 +24,11 @@ public class ExpressionExecutionContext
|
|||
CancellationToken = cancellationToken;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A register of computer memory.
|
||||
/// </summary>
|
||||
public Register Register { get; }
|
||||
|
||||
public Workflow Workflow { get; }
|
||||
public IDictionary<string, object> Input { get; }
|
||||
public IDictionary<object, object?> TransientProperties { get; }
|
||||
|
|
|
|||
3
src/core/Elsa.Core/Models/NamedOutput.cs
Normal file
3
src/core/Elsa.Core/Models/NamedOutput.cs
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
namespace Elsa.Models;
|
||||
|
||||
public record NamedOutput(string Name, Output Value);
|
||||
|
|
@ -129,7 +129,7 @@ public class WorkflowExecutionContext
|
|||
foreach (var bookmark in bookmarks)
|
||||
_bookmarks.Remove(bookmark);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears all bookmarks from all <see cref="ActivityExecutionContexts"/>.
|
||||
/// </summary>
|
||||
|
|
@ -142,7 +142,7 @@ public class WorkflowExecutionContext
|
|||
public void TransitionTo(WorkflowSubStatus subStatus)
|
||||
{
|
||||
var targetStatus = GetMainStatus(subStatus);
|
||||
|
||||
|
||||
if (!ValidateStatusTransition(SubStatus, subStatus))
|
||||
throw new Exception($"Cannot transition from {Status} to {targetStatus}");
|
||||
|
||||
|
|
@ -165,4 +165,6 @@ public class WorkflowExecutionContext
|
|||
var currentMainStatus = GetMainStatus(currentSubStatus);
|
||||
return currentMainStatus != WorkflowStatus.Finished;
|
||||
}
|
||||
|
||||
private IEnumerable<Register> GetMergedRegistersView() => new[] { Register }.Concat(ActivityExecutionContexts.Select(x => x.ExpressionExecutionContext.Register)).ToList();
|
||||
}
|
||||
|
|
@ -28,13 +28,13 @@ public class ActivityDescriber : IActivityDescriber
|
|||
public ValueTask<ActivityDescriptor> DescribeActivityAsync(Type activityType, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var activityAttr = activityType.GetCustomAttribute<ActivityAttribute>();
|
||||
var ns = activityAttr?.Namespace ?? TypeNameHelper.GenerateNamespace(activityType);
|
||||
var ns = activityAttr?.Namespace ?? ActivityTypeNameHelper.GenerateNamespace(activityType);
|
||||
var typeName = activityAttr?.TypeName ?? activityType.Name;
|
||||
var fullTypeName = $"{ns}.{typeName}";
|
||||
var displayNameAttr = activityType.GetCustomAttribute<DisplayNameAttribute>();
|
||||
var displayName = displayNameAttr?.DisplayName ?? activityAttr?.DisplayName ?? typeName.Humanize(LetterCasing.Title);
|
||||
var categoryAttr = activityType.GetCustomAttribute<CategoryAttribute>();
|
||||
var category = categoryAttr?.Category ?? activityAttr?.Category ?? TypeNameHelper.GetCategoryFromNamespace(ns) ?? "Miscellaneous";
|
||||
var category = categoryAttr?.Category ?? activityAttr?.Category ?? ActivityTypeNameHelper.GetCategoryFromNamespace(ns) ?? "Miscellaneous";
|
||||
var descriptionAttr = activityType.GetCustomAttribute<DescriptionAttribute>();
|
||||
var description = descriptionAttr?.Description ?? activityAttr?.Description;
|
||||
|
||||
|
|
|
|||
|
|
@ -64,6 +64,6 @@ public class HttpEndpoint : Trigger<HttpRequestModel>
|
|||
// Generate bookmark data for path and selected methods.
|
||||
var path = context.Get(Path);
|
||||
var methods = context.Get(SupportedMethods);
|
||||
return methods!.Select(x => new HttpBookmarkData(path!, x.ToLowerInvariant())).Cast<object>().ToArray();
|
||||
return methods!.Select(x => new HttpEndpointBookmarkData(path!, x.ToLowerInvariant())).Cast<object>().ToArray();
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\core\Elsa.Core\Elsa.Core.csproj" />
|
||||
<ProjectReference Include="..\..\runtime\Elsa.Runtime\Elsa.Runtime.csproj" />
|
||||
<ProjectReference Include="..\..\scripting\Elsa.Scripting.JavaScript\Elsa.Scripting.JavaScript.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -20,8 +21,4 @@
|
|||
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Scripting" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Elsa.Helpers;
|
||||
using Elsa.Modules.Http.Models;
|
||||
using Elsa.Modules.Http.Services;
|
||||
using Elsa.Persistence.Entities;
|
||||
|
||||
namespace Elsa.Modules.Http.Extensions;
|
||||
|
||||
public static class RouteTableExtensions
|
||||
{
|
||||
|
||||
public static void AddRoutes(this IRouteTable routeTable, IEnumerable<WorkflowTrigger> triggers)
|
||||
{
|
||||
var paths = Filter(triggers).Select(Deserialize).Select(x => x.Path).ToList();
|
||||
routeTable.AddRange(paths);
|
||||
}
|
||||
|
||||
public static void AddRoutes(this IRouteTable routeTable, IEnumerable<WorkflowBookmark> bookmarks)
|
||||
{
|
||||
var paths = Filter(bookmarks).Select(Deserialize).Select(x => x.Path).ToList();
|
||||
routeTable.AddRange(paths);
|
||||
}
|
||||
|
||||
public static void RemoveRoutes(this IRouteTable routeTable, IEnumerable<WorkflowTrigger> triggers)
|
||||
{
|
||||
var paths = Filter(triggers).Select(Deserialize).Select(x => x.Path).ToList();
|
||||
routeTable.RemoveRange(paths);
|
||||
}
|
||||
|
||||
public static void RemoveRoutes(this IRouteTable routeTable, IEnumerable<WorkflowBookmark> bookmarks)
|
||||
{
|
||||
var paths = Filter(bookmarks).Select(Deserialize).Select(x => x.Path).ToList();
|
||||
routeTable.RemoveRange(paths);
|
||||
}
|
||||
|
||||
private static IEnumerable<WorkflowTrigger> Filter(IEnumerable<WorkflowTrigger> triggers) => triggers.Where(x => x.Name == ActivityTypeNameHelper.GenerateTypeName<HttpEndpoint>());
|
||||
private static IEnumerable<WorkflowBookmark> Filter(IEnumerable<WorkflowBookmark> triggers) => triggers.Where(x => x.Name == ActivityTypeNameHelper.GenerateTypeName<HttpEndpoint>());
|
||||
private static HttpEndpointBookmarkData Deserialize(WorkflowTrigger trigger) => Deserialize(trigger.Data!);
|
||||
private static HttpEndpointBookmarkData Deserialize(WorkflowBookmark bookmark) => Deserialize(bookmark.Data!);
|
||||
private static HttpEndpointBookmarkData Deserialize(string model) => JsonSerializer.Deserialize<HttpEndpointBookmarkData>(model)!;
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
|
||||
using Elsa.Mediator.Extensions;
|
||||
using Elsa.Modules.Http.Handlers;
|
||||
using Elsa.Modules.Http.Implementations;
|
||||
using Elsa.Modules.Http.Services;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public static class ServiceCollectionExtensions
|
||||
|
|
@ -9,6 +11,9 @@ public static class ServiceCollectionExtensions
|
|||
public static IServiceCollection AddHttpActivityServices(this IServiceCollection services)
|
||||
{
|
||||
return services
|
||||
.AddSingleton<IRouteMatcher, RouteMatcher>()
|
||||
.AddSingleton<IRouteTable, RouteTable>()
|
||||
.AddNotificationHandlersFrom<UpdateRouteTable>()
|
||||
.AddHttpContextAccessor();
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Http;
|
|||
|
||||
namespace Elsa.Modules.Http.Handlers;
|
||||
|
||||
// ReSharper disable once ClassWithVirtualMembersNeverInherited.Global
|
||||
public class DefaultHttpEndpointWorkflowFaultHandler : IHttpEndpointWorkflowFaultHandler
|
||||
{
|
||||
public virtual async ValueTask HandleAsync(HttpEndpointFaultedWorkflowContext context)
|
||||
|
|
|
|||
33
src/modules/Elsa.Modules.Http/Handlers/UpdateRouteTable.cs
Normal file
33
src/modules/Elsa.Modules.Http/Handlers/UpdateRouteTable.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Mediator.Services;
|
||||
using Elsa.Modules.Http.Extensions;
|
||||
using Elsa.Modules.Http.Services;
|
||||
using Elsa.Runtime.Models;
|
||||
using Elsa.Runtime.Notifications;
|
||||
|
||||
namespace Elsa.Modules.Http.Handlers
|
||||
{
|
||||
public class UpdateRouteTable :
|
||||
INotificationHandler<WorkflowTriggersIndexed>,
|
||||
INotificationHandler<WorkflowBookmarksIndexed>
|
||||
{
|
||||
private readonly IRouteTable _routeTable;
|
||||
public UpdateRouteTable(IRouteTable routeTable) => _routeTable = routeTable;
|
||||
|
||||
public Task HandleAsync(WorkflowTriggersIndexed notification, CancellationToken cancellationToken)
|
||||
{
|
||||
_routeTable.RemoveRoutes(notification.IndexedWorkflowTriggers.RemovedTriggers);
|
||||
_routeTable.AddRoutes(notification.IndexedWorkflowTriggers.AddedTriggers);
|
||||
_routeTable.AddRoutes(notification.IndexedWorkflowTriggers.UnchangedTriggers);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task HandleAsync(WorkflowBookmarksIndexed notification, CancellationToken cancellationToken)
|
||||
{
|
||||
_routeTable.RemoveRoutes(notification.IndexedWorkflowBookmarks.RemovedBookmarks);
|
||||
_routeTable.AddRoutes(notification.IndexedWorkflowBookmarks.AddedBookmarks);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -35,8 +35,8 @@ public class HttpTriggerMiddleware
|
|||
var request = httpContext.Request;
|
||||
var method = request.Method!.ToLowerInvariant();
|
||||
var abortToken = httpContext.RequestAborted;
|
||||
var hash = _hasher.Hash(new HttpBookmarkData(path, method));
|
||||
var activityTypeName = TypeNameHelper.GenerateTypeName<HttpEndpoint>();
|
||||
var hash = _hasher.Hash(new HttpEndpointBookmarkData(path, method));
|
||||
var activityTypeName = ActivityTypeNameHelper.GenerateTypeName<HttpEndpoint>();
|
||||
var routeData = GetRouteData(httpContext, routeMatcher, path);
|
||||
|
||||
var requestModel = new HttpRequestModel(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.Mediator.Services;
|
||||
using Elsa.Scripting.JavaScript.Notifications;
|
||||
|
||||
namespace Elsa.Modules.Http.Scripting;
|
||||
|
||||
public class ConfigureJavaScriptEngine : INotificationHandler<EvaluatingJavaScript>
|
||||
{
|
||||
public Task HandleAsync(EvaluatingJavaScript notification, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
@ -75,6 +75,7 @@ public static class ServiceCollectionExtensions
|
|||
.AddExpressionHandler<LiteralExpressionHandler, LiteralExpression>()
|
||||
.AddExpressionHandler<DelegateExpressionHandler, DelegateExpression>()
|
||||
.AddExpressionHandler<VariableExpressionHandler, VariableExpression>()
|
||||
.AddExpressionHandler<JsonExpressionHandler, JsonExpression>()
|
||||
.AddExpressionHandler<OutputExpressionHandler, OutputExpression>()
|
||||
.AddExpressionHandler<ElsaExpressionHandler, ElsaExpression>();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue