From e6ce1cebb31b460883e78756ad5356dbe8d2aa53 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 8 Mar 2023 00:31:51 +0100 Subject: [PATCH] Stash --- .../WorkflowDefinitions/Post/Endpoint.cs | 2 +- .../Activities/Composite.cs | 2 +- .../Attributes/JsonExpandableAttribute.cs | 9 +++ .../Converters/JsonExpandableConverter.cs | 57 +++++++++++++++++++ .../SerializerOptionsProvider.cs | 7 ++- .../WorkflowDefinitionActivity.cs | 5 +- 6 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 src/modules/Elsa.Workflows.Core/Attributes/JsonExpandableAttribute.cs create mode 100644 src/modules/Elsa.Workflows.Core/Serialization/Converters/JsonExpandableConverter.cs diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Post/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Post/Endpoint.cs index a80350c12..de8f194e4 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Post/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowDefinitions/Post/Endpoint.cs @@ -64,7 +64,7 @@ internal class Post : ElsaEndpoint(); diff --git a/src/modules/Elsa.Workflows.Core/Activities/Composite.cs b/src/modules/Elsa.Workflows.Core/Activities/Composite.cs index c5953a6a7..05925dd3e 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/Composite.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/Composite.cs @@ -43,7 +43,7 @@ public abstract class Composite : Activity, IVariableContainer /// [Port] [Browsable(false)] - [JsonIgnore] // Composite activities' Root is intended to be constructed from code only. + //[JsonExpandable] // Composite activities' Root is intended to be constructed from code only. public IActivity Root { get; set; } = new Sequence(); /// diff --git a/src/modules/Elsa.Workflows.Core/Attributes/JsonExpandableAttribute.cs b/src/modules/Elsa.Workflows.Core/Attributes/JsonExpandableAttribute.cs new file mode 100644 index 000000000..82f4ac540 --- /dev/null +++ b/src/modules/Elsa.Workflows.Core/Attributes/JsonExpandableAttribute.cs @@ -0,0 +1,9 @@ +namespace Elsa.Workflows.Core.Attributes; + +/// +/// Used by a custom converter to indicate that the property should be expanded into a JSON object. +/// +[AttributeUsage(AttributeTargets.Property)] +public class JsonExpandableAttribute : Attribute +{ +} \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Serialization/Converters/JsonExpandableConverter.cs b/src/modules/Elsa.Workflows.Core/Serialization/Converters/JsonExpandableConverter.cs new file mode 100644 index 000000000..80d6390bd --- /dev/null +++ b/src/modules/Elsa.Workflows.Core/Serialization/Converters/JsonExpandableConverter.cs @@ -0,0 +1,57 @@ +using System.Reflection; +using System.Text.Json; +using System.Text.Json.Serialization; +using Elsa.Extensions; +using Elsa.Workflows.Core.Attributes; + +namespace Elsa.Workflows.Core.Serialization.Converters; + +/// +/// Ignores properties with the attribute. +/// +public class JsonExpandableConverter : JsonConverter +{ + /// + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } + + /// + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + writer.WriteStartObject(); + + var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); + var newOptions = new JsonSerializerOptions(options); + + newOptions.Converters.RemoveWhere(x => x is JsonExpandableConverterFactory); + + foreach (var property in properties) + { + if (property.GetCustomAttribute() != null) + continue; + + var propName = options.PropertyNamingPolicy?.ConvertName(property.Name) ?? property.Name; + writer.WritePropertyName(propName); + JsonSerializer.Serialize(writer, property.GetValue(value), newOptions); + } + + writer.WriteEndObject(); + } +} + +/// +/// A that creates instances. +/// +public class JsonExpandableConverterFactory : JsonConverterFactory +{ + /// + public override bool CanConvert(Type typeToConvert) => typeof(T).IsAssignableFrom(typeToConvert); + + /// + public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + return new JsonExpandableConverter(); + } +} \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Core/Serialization/SerializerOptionsProvider.cs b/src/modules/Elsa.Workflows.Core/Serialization/SerializerOptionsProvider.cs index ffc225c5c..b09e37ad1 100644 --- a/src/modules/Elsa.Workflows.Core/Serialization/SerializerOptionsProvider.cs +++ b/src/modules/Elsa.Workflows.Core/Serialization/SerializerOptionsProvider.cs @@ -21,7 +21,12 @@ public class SerializerOptionsProvider public JsonSerializerOptions CreateApiOptions(ReferenceHandler? referenceHandler = default) => CreateDefaultOptions(referenceHandler ?? ReferenceHandler.IgnoreCycles); - public JsonSerializerOptions CreatePersistenceOptions(ReferenceHandler? referenceHandler = default) => CreateDefaultOptions(referenceHandler ?? ReferenceHandler.IgnoreCycles); + public JsonSerializerOptions CreatePersistenceOptions(ReferenceHandler? referenceHandler = default) + { + var options = CreateDefaultOptions(referenceHandler ?? ReferenceHandler.IgnoreCycles); + options.Converters.Add(Create>()); + return options; + } public JsonSerializerOptions CreateDefaultOptions(ReferenceHandler? referenceHandling = default) { diff --git a/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivity.cs b/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivity.cs index f8c97bc53..6292907b3 100644 --- a/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivity.cs +++ b/src/modules/Elsa.Workflows.Management/Activities/WorkflowDefinitionActivity/WorkflowDefinitionActivity.cs @@ -17,7 +17,10 @@ namespace Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity; [Browsable(false)] public class WorkflowDefinitionActivity : Activity, IInitializable { - internal IActivity Root { get; set; } = default!; + /// + /// The activity to schedule for execution. + /// + public IActivity Root { get; set; } = default!; /// /// The definition ID of the workflow to schedule for execution.