This commit is contained in:
Sipke Schoorstra 2023-03-08 00:31:51 +01:00
parent 21f8980adb
commit e6ce1cebb3
6 changed files with 78 additions and 4 deletions

View file

@ -64,7 +64,7 @@ internal class Post : ElsaEndpoint<WorkflowDefinitionRequest, WorkflowDefinition
// Update the draft with the received model.
var root = request.Root ?? new Sequence();
var serializerOptions = _serializerOptionsProvider.CreateApiOptions();
var serializerOptions = _serializerOptionsProvider.CreatePersistenceOptions();
var stringData = JsonSerializer.Serialize(root, serializerOptions);
var variables = _variableDefinitionMapper.Map(request.Variables).ToList();
var inputs = request.Inputs ?? new List<InputDefinition>();

View file

@ -43,7 +43,7 @@ public abstract class Composite : Activity, IVariableContainer
/// </summary>
[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();
/// <inheritdoc />

View file

@ -0,0 +1,9 @@
namespace Elsa.Workflows.Core.Attributes;
/// <summary>
/// Used by a custom converter to indicate that the property should be expanded into a JSON object.
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class JsonExpandableAttribute : Attribute
{
}

View file

@ -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;
/// <summary>
/// Ignores properties with the <see cref="JsonExpandableAttribute"/> attribute.
/// </summary>
public class JsonExpandableConverter<T> : JsonConverter<T>
{
/// <inheritdoc />
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
/// <inheritdoc />
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<T>);
foreach (var property in properties)
{
if (property.GetCustomAttribute<JsonExpandableAttribute>() != null)
continue;
var propName = options.PropertyNamingPolicy?.ConvertName(property.Name) ?? property.Name;
writer.WritePropertyName(propName);
JsonSerializer.Serialize(writer, property.GetValue(value), newOptions);
}
writer.WriteEndObject();
}
}
/// <summary>
/// A <see cref="JsonConverterFactory"/> that creates <see cref="JsonExpandableConverter{T}"/> instances.
/// </summary>
public class JsonExpandableConverterFactory<T> : JsonConverterFactory
{
/// <inheritdoc />
public override bool CanConvert(Type typeToConvert) => typeof(T).IsAssignableFrom(typeToConvert);
/// <inheritdoc />
public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
{
return new JsonExpandableConverter<T>();
}
}

View file

@ -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<JsonExpandableConverterFactory<IActivity>>());
return options;
}
public JsonSerializerOptions CreateDefaultOptions(ReferenceHandler? referenceHandling = default)
{

View file

@ -17,7 +17,10 @@ namespace Elsa.Workflows.Management.Activities.WorkflowDefinitionActivity;
[Browsable(false)]
public class WorkflowDefinitionActivity : Activity, IInitializable
{
internal IActivity Root { get; set; } = default!;
/// <summary>
/// The activity to schedule for execution.
/// </summary>
public IActivity Root { get; set; } = default!;
/// <summary>
/// The definition ID of the workflow to schedule for execution.