Add synchronous serialization methods and mark async as obsolete
Implemented synchronous methods for serialization and deserialization while marking the asynchronous methods as obsolete across various storage and serialization services. This includes updates to handle serialization within the Save and Load methods, enhancing performance by avoiding unnecessary Task usage.
This commit is contained in:
parent
7609b0e7ca
commit
2e1ed995da
41
src/bundles/Elsa.Server.Web/SampleWorkflow.cs
Normal file
41
src/bundles/Elsa.Server.Web/SampleWorkflow.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
using Elsa.Expressions.Models;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Scheduling.Activities;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Activities;
|
||||
using Elsa.Workflows.Contracts;
|
||||
|
||||
namespace Elsa.Server.Web;
|
||||
|
||||
public class SampleWorkflow : WorkflowBase
|
||||
{
|
||||
protected override void Build(IWorkflowBuilder workflow)
|
||||
{
|
||||
// The WithVariable method ensures that the created variable will be added to the Workflow's Variables collection, which is required for persistent variables.
|
||||
var variable1 = workflow.WithVariable<string>("Foo").WithWorkflowStorage();
|
||||
|
||||
workflow.Variables =
|
||||
[
|
||||
variable1
|
||||
];
|
||||
|
||||
workflow.Root = new Sequence
|
||||
{
|
||||
Activities =
|
||||
{
|
||||
new StartAt(DateTimeOffset.UtcNow + TimeSpan.FromSeconds(5))
|
||||
{
|
||||
CanStartWorkflow = true
|
||||
},
|
||||
new WriteLine(variable1),
|
||||
new SetVariable
|
||||
{
|
||||
Variable = variable1,
|
||||
Value = new (Literal.From("Bar"))
|
||||
},
|
||||
new Delay(TimeSpan.FromSeconds(1)),
|
||||
new WriteLine(variable1)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"Default": "Warning",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information",
|
||||
"OpenTelemetry": "Debug"
|
||||
|
|
|
|||
|
|
@ -38,14 +38,14 @@ public class DapperActivityExecutionRecordStore : IActivityExecutionStore
|
|||
/// <inheritdoc />
|
||||
public async Task SaveAsync(ActivityExecutionRecord record, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var mappedRecord = await Map(record, cancellationToken);
|
||||
var mappedRecord = Map(record, cancellationToken);
|
||||
await _store.SaveAsync(mappedRecord, PrimaryKeyName, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task SaveManyAsync(IEnumerable<ActivityExecutionRecord> records, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var mappedRecords = await Task.WhenAll(records.Select(async x => await Map(x, cancellationToken)));
|
||||
var mappedRecords = records.Select(x => Map(x, cancellationToken));
|
||||
await _store.SaveManyAsync(mappedRecords, PrimaryKeyName, cancellationToken);
|
||||
}
|
||||
|
||||
|
|
@ -53,21 +53,21 @@ public class DapperActivityExecutionRecordStore : IActivityExecutionStore
|
|||
public async Task<ActivityExecutionRecord?> FindAsync(ActivityExecutionRecordFilter filter, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var record = await _store.FindAsync(q => ApplyFilter(q, filter), cancellationToken);
|
||||
return record == null ? null : await MapAsync(record, cancellationToken);
|
||||
return record == null ? null : Map(record, cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<ActivityExecutionRecord>> FindManyAsync<TOrderBy>(ActivityExecutionRecordFilter filter, ActivityExecutionRecordOrder<TOrderBy> order, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var records = await _store.FindManyAsync(q => ApplyFilter(q, filter), order.KeySelector.GetPropertyName(), order.Direction, cancellationToken);
|
||||
return await Task.WhenAll(records.Select(async x => await MapAsync(x, cancellationToken)));
|
||||
return records.Select( x => Map(x, cancellationToken)).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IEnumerable<ActivityExecutionRecord>> FindManyAsync(ActivityExecutionRecordFilter filter, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var records = await _store.FindManyAsync(q => ApplyFilter(q, filter), cancellationToken);
|
||||
return await Task.WhenAll(records.Select(async x => await MapAsync(x, cancellationToken)));
|
||||
return records.Select( x => Map(x, cancellationToken)).ToList();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
@ -115,7 +115,7 @@ public class DapperActivityExecutionRecordStore : IActivityExecutionStore
|
|||
}
|
||||
}
|
||||
|
||||
private async ValueTask<ActivityExecutionRecordRecord> Map(ActivityExecutionRecord source, CancellationToken cancellationToken)
|
||||
private ActivityExecutionRecordRecord Map(ActivityExecutionRecord source, CancellationToken cancellationToken)
|
||||
{
|
||||
return new ActivityExecutionRecordRecord
|
||||
{
|
||||
|
|
@ -130,15 +130,15 @@ public class DapperActivityExecutionRecordStore : IActivityExecutionStore
|
|||
HasBookmarks = source.HasBookmarks,
|
||||
Status = source.Status.ToString(),
|
||||
ActivityTypeVersion = source.ActivityTypeVersion,
|
||||
SerializedActivityState = source.ActivityState != null ? await _safeSerializer.SerializeAsync(source.ActivityState, cancellationToken) : null,
|
||||
SerializedPayload = source.Payload != null ? await _safeSerializer.SerializeAsync(source.Payload, cancellationToken) : null,
|
||||
SerializedOutputs = source.Outputs?.Any() == true ? await _safeSerializer.SerializeAsync(source.Outputs, cancellationToken) : null,
|
||||
SerializedActivityState = source.ActivityState != null ? _safeSerializer.Serialize(source.ActivityState, cancellationToken) : null,
|
||||
SerializedPayload = source.Payload != null ? _safeSerializer.Serialize(source.Payload, cancellationToken) : null,
|
||||
SerializedOutputs = source.Outputs?.Any() == true ? _safeSerializer.Serialize(source.Outputs, cancellationToken) : null,
|
||||
SerializedException = source.Exception != null ? _payloadSerializer.Serialize(source.Exception) : null,
|
||||
SerializedProperties = source.Properties.Any() ? await _safeSerializer.SerializeAsync(source.Properties, cancellationToken) : null
|
||||
SerializedProperties = source.Properties.Any() ? _safeSerializer.Serialize(source.Properties, cancellationToken) : null
|
||||
};
|
||||
}
|
||||
|
||||
private async ValueTask<ActivityExecutionRecord> MapAsync(ActivityExecutionRecordRecord source, CancellationToken cancellationToken)
|
||||
private ActivityExecutionRecord Map(ActivityExecutionRecordRecord source, CancellationToken cancellationToken)
|
||||
{
|
||||
return new ActivityExecutionRecord
|
||||
{
|
||||
|
|
@ -153,11 +153,11 @@ public class DapperActivityExecutionRecordStore : IActivityExecutionStore
|
|||
HasBookmarks = source.HasBookmarks,
|
||||
Status = Enum.Parse<ActivityStatus>(source.Status),
|
||||
ActivityTypeVersion = source.ActivityTypeVersion,
|
||||
ActivityState = source.SerializedActivityState != null ? _payloadSerializer.Deserialize<IDictionary<string, object>>(source.SerializedActivityState) : default,
|
||||
Payload = source.SerializedPayload != null ? await _safeSerializer.DeserializeAsync<IDictionary<string, object>>(source.SerializedPayload, cancellationToken) : default,
|
||||
Outputs = source.SerializedOutputs != null ? await _safeSerializer.DeserializeAsync<IDictionary<string, object?>>(source.SerializedOutputs, cancellationToken) : default,
|
||||
Exception = source.SerializedException != null ? _payloadSerializer.Deserialize<ExceptionState>(source.SerializedException) : default,
|
||||
Properties = source.SerializedProperties != null ? await _safeSerializer.DeserializeAsync<IDictionary<string, object>>(source.SerializedProperties, cancellationToken) : default
|
||||
ActivityState = source.SerializedActivityState != null ? _payloadSerializer.Deserialize<IDictionary<string, object>>(source.SerializedActivityState) : null,
|
||||
Payload = source.SerializedPayload != null ? _safeSerializer.Deserialize<IDictionary<string, object>>(source.SerializedPayload, cancellationToken) : null,
|
||||
Outputs = source.SerializedOutputs != null ? _safeSerializer.Deserialize<IDictionary<string, object?>>(source.SerializedOutputs, cancellationToken) : null,
|
||||
Exception = source.SerializedException != null ? _payloadSerializer.Deserialize<ExceptionState>(source.SerializedException) : null,
|
||||
Properties = source.SerializedProperties != null ? _safeSerializer.Deserialize<IDictionary<string, object>>(source.SerializedProperties, cancellationToken) : null
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,12 +83,12 @@ public class EFCoreActivityExecutionStore(
|
|||
{
|
||||
entity = entity.SanitizeLogMessage();
|
||||
var compressionAlgorithm = options.Value.CompressionAlgorithm ?? nameof(None);
|
||||
var serializedActivityState = entity.ActivityState != null ? await safeSerializer.SerializeAsync(entity.ActivityState, cancellationToken) : null;
|
||||
var serializedActivityState = entity.ActivityState != null ? safeSerializer.Serialize(entity.ActivityState, cancellationToken) : null;
|
||||
var compressedSerializedActivityState = serializedActivityState != null ? await compressionCodecResolver.Resolve(compressionAlgorithm).CompressAsync(serializedActivityState, cancellationToken) : null;
|
||||
|
||||
dbContext.Entry(entity).Property("SerializedActivityState").CurrentValue = compressedSerializedActivityState;
|
||||
dbContext.Entry(entity).Property("SerializedActivityStateCompressionAlgorithm").CurrentValue = compressionAlgorithm;
|
||||
dbContext.Entry(entity).Property("SerializedOutputs").CurrentValue = entity.Outputs?.Any() == true ? await safeSerializer.SerializeAsync(entity.Outputs, cancellationToken) : null;
|
||||
dbContext.Entry(entity).Property("SerializedOutputs").CurrentValue = entity.Outputs?.Any() == true ? safeSerializer.Serialize(entity.Outputs, cancellationToken) : null;
|
||||
dbContext.Entry(entity).Property("SerializedProperties").CurrentValue = entity.Properties.Any() ? payloadSerializer.Serialize(entity.Properties) : null;
|
||||
dbContext.Entry(entity).Property("SerializedException").CurrentValue = entity.Exception != null ? payloadSerializer.Serialize(entity.Exception) : null;
|
||||
dbContext.Entry(entity).Property("SerializedPayload").CurrentValue = entity.Payload?.Any() == true ? payloadSerializer.Serialize(entity.Payload) : null;
|
||||
|
|
|
|||
|
|
@ -87,8 +87,8 @@ public class EFCoreWorkflowExecutionLogStore : IWorkflowExecutionLogStore
|
|||
private async ValueTask OnSaveAsync(RuntimeElsaDbContext dbContext, WorkflowExecutionLogRecord entity, CancellationToken cancellationToken)
|
||||
{
|
||||
entity = entity.SanitizeLogMessage();
|
||||
dbContext.Entry(entity).Property("SerializedActivityState").CurrentValue = entity.ActivityState?.Any() == true ? await _safeSerializer.SerializeAsync(entity.ActivityState, cancellationToken) : default;
|
||||
dbContext.Entry(entity).Property("SerializedPayload").CurrentValue = entity.Payload != null ? await _safeSerializer.SerializeAsync(entity.Payload, cancellationToken) : default;
|
||||
dbContext.Entry(entity).Property("SerializedActivityState").CurrentValue = entity.ActivityState?.Any() == true ? _safeSerializer.Serialize(entity.ActivityState, cancellationToken) : null;
|
||||
dbContext.Entry(entity).Property("SerializedPayload").CurrentValue = entity.Payload != null ? _safeSerializer.Serialize(entity.Payload, cancellationToken) : null;
|
||||
}
|
||||
|
||||
private async ValueTask OnLoadAsync(RuntimeElsaDbContext dbContext, WorkflowExecutionLogRecord? entity, CancellationToken cancellationToken)
|
||||
|
|
|
|||
|
|
@ -121,10 +121,10 @@ internal class Export : ElsaEndpointWithMapper<Request, WorkflowInstanceMapper>
|
|||
var executionLogRecords = request.IncludeWorkflowExecutionLog ? await LoadWorkflowExecutionLogRecordsAsync(workflowState.Id, cancellationToken) : default;
|
||||
var activityExecutionLogRecords = request.IncludeActivityExecutionLog ? await LoadActivityExecutionLogRecordsAsync(workflowState.Id, cancellationToken) : default;
|
||||
var bookmarks = request.IncludeBookmarks ? await LoadBookmarksAsync(workflowState.Id, cancellationToken) : null;
|
||||
var workflowStateElement = await _workflowStateSerializer.SerializeToElementAsync(workflowState, cancellationToken);
|
||||
var workflowStateElement = _workflowStateSerializer.SerializeToElement(workflowState, cancellationToken);
|
||||
var bookmarksElement = bookmarks != null ? SerializeBookmarks(bookmarks) : default(JsonElement?);
|
||||
var executionLogRecordsElement = executionLogRecords != null ? await _safeSerializer.SerializeToElementAsync(executionLogRecords, cancellationToken) : default(JsonElement?);
|
||||
var activityExecutionLogRecordsElement = activityExecutionLogRecords != null ? await _safeSerializer.SerializeToElementAsync(activityExecutionLogRecords, cancellationToken) : default(JsonElement?);
|
||||
var executionLogRecordsElement = executionLogRecords != null ? _safeSerializer.SerializeToElement(executionLogRecords, cancellationToken) : default(JsonElement?);
|
||||
var activityExecutionLogRecordsElement = activityExecutionLogRecords != null ? _safeSerializer.SerializeToElement(activityExecutionLogRecords, cancellationToken) : default(JsonElement?);
|
||||
var model = new ExportedWorkflowState(workflowStateElement, bookmarksElement, activityExecutionLogRecordsElement, executionLogRecordsElement);
|
||||
return model;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,13 +137,13 @@ internal class Import : ElsaEndpointWithoutRequest<Response>
|
|||
|
||||
if (model.ActivityExecutionRecords != null)
|
||||
{
|
||||
var activityExecutionRecords = await _safeSerializer.DeserializeAsync<ICollection<ActivityExecutionRecord>>(model.ActivityExecutionRecords.Value, cancellationToken);
|
||||
var activityExecutionRecords = _safeSerializer.Deserialize<ICollection<ActivityExecutionRecord>>(model.ActivityExecutionRecords.Value, cancellationToken);
|
||||
await _activityExecutionStore.SaveManyAsync(activityExecutionRecords, cancellationToken);
|
||||
}
|
||||
|
||||
if (model.WorkflowExecutionLogRecords != null)
|
||||
{
|
||||
var workflowExecutionLogRecords = await _safeSerializer.DeserializeAsync<ICollection<WorkflowExecutionLogRecord>>(model.WorkflowExecutionLogRecords.Value, cancellationToken);
|
||||
var workflowExecutionLogRecords = _safeSerializer.Deserialize<ICollection<WorkflowExecutionLogRecord>>(model.WorkflowExecutionLogRecords.Value, cancellationToken);
|
||||
await _workflowExecutionLogStore.SaveManyAsync(workflowExecutionLogRecords, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,24 +11,52 @@ public interface ISafeSerializer
|
|||
/// <summary>
|
||||
/// Serializes the specified state.
|
||||
/// </summary>
|
||||
[Obsolete("Use the non-async Serialize instead.")]
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
ValueTask<string> SerializeAsync(object? value, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified state to a <see cref="JsonElement"/> object.
|
||||
/// </summary>
|
||||
[Obsolete("Use the non-async SerializeToElement instead.")]
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
ValueTask<JsonElement> SerializeToElementAsync(object? value, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified state.
|
||||
/// </summary>
|
||||
[Obsolete("Use the non-async Deserialize instead.")]
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
ValueTask<T> DeserializeAsync<T>(string json, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified state.
|
||||
/// </summary>
|
||||
[Obsolete("Use the non-async Deserialize instead.")]
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
ValueTask<T> DeserializeAsync<T>(JsonElement element, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified state.
|
||||
/// </summary>
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
string Serialize(object? value, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified state to a <see cref="JsonElement"/> object.
|
||||
/// </summary>
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
JsonElement SerializeToElement(object? value, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified state.
|
||||
/// </summary>
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
T Deserialize<T>(string json, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified state.
|
||||
/// </summary>
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
T Deserialize<T>(JsonElement element, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -16,8 +16,9 @@ public interface IWorkflowStateSerializer
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The serialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version Serialize instead.")]
|
||||
Task<string> SerializeAsync(WorkflowState workflowState, CancellationToken cancellationToken = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified workflow state.
|
||||
/// </summary>
|
||||
|
|
@ -25,8 +26,18 @@ public interface IWorkflowStateSerializer
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The serialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
string Serialize(WorkflowState workflowState, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified workflow state.
|
||||
/// </summary>
|
||||
/// <param name="workflowState">The workflow state to serialize.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The serialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version SerializeToUtfBytes instead.")]
|
||||
Task<byte[]> SerializeToUtfBytesAsync(WorkflowState workflowState, CancellationToken cancellationToken = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified workflow state.
|
||||
/// </summary>
|
||||
|
|
@ -34,8 +45,18 @@ public interface IWorkflowStateSerializer
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The serialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
byte[] SerializeToUtfBytes(WorkflowState workflowState, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified workflow state.
|
||||
/// </summary>
|
||||
/// <param name="workflowState">The workflow state to serialize.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The serialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version SerializeToElement instead.")]
|
||||
Task<JsonElement> SerializeToElementAsync(WorkflowState workflowState, CancellationToken cancellationToken = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified workflow state.
|
||||
/// </summary>
|
||||
|
|
@ -43,32 +64,81 @@ public interface IWorkflowStateSerializer
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The serialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
JsonElement SerializeToElement(WorkflowState workflowState, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified workflow state.
|
||||
/// </summary>
|
||||
/// <param name="workflowState">The workflow state to serialize.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The serialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version Serialize instead.")]
|
||||
Task<string> SerializeAsync(object workflowState, CancellationToken cancellationToken = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the specified workflow state.
|
||||
/// </summary>
|
||||
/// <param name="workflowState">The workflow state to serialize.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The serialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
string Serialize(object workflowState, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified serialized state.
|
||||
/// </summary>
|
||||
/// <param name="serializedState">The serialized state.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The deserialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version Deserialize instead.")]
|
||||
Task<WorkflowState> DeserializeAsync(string serializedState, CancellationToken cancellationToken = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified serialized state.
|
||||
/// </summary>
|
||||
/// <param name="serializedState">The serialized state.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The deserialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")]
|
||||
WorkflowState Deserialize(string serializedState, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified serialized state.
|
||||
/// </summary>
|
||||
/// <param name="serializedState">The serialized state.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The deserialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version Deserialize instead.")]
|
||||
Task<WorkflowState> DeserializeAsync(JsonElement serializedState, CancellationToken cancellationToken = default);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified serialized state.
|
||||
/// </summary>
|
||||
/// <param name="serializedState">The serialized state.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The deserialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")]
|
||||
WorkflowState Deserialize(JsonElement serializedState, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified serialized state.
|
||||
/// </summary>
|
||||
/// <param name="serializedState">The serialized state.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The deserialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version Deserialize instead.")]
|
||||
Task<T> DeserializeAsync<T>(string serializedState, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes the specified serialized state.
|
||||
/// </summary>
|
||||
/// <param name="serializedState">The serialized state.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <returns>The deserialized workflow state.</returns>
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")]
|
||||
T Deserialize<T>(string serializedState, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -253,7 +253,7 @@ public static class ActivityExecutionContextExtensions
|
|||
// Serializing the value ensures we store a copy of the value and not a reference to the input, which may change over time.
|
||||
if (inputDescriptor.IsSerializable != false)
|
||||
{
|
||||
var serializedValue = await context.GetRequiredService<ISafeSerializer>().SerializeToElementAsync(value);
|
||||
var serializedValue = context.GetRequiredService<ISafeSerializer>().SerializeToElement(value);
|
||||
context.ActivityState[inputDescriptor.Name] = serializedValue;
|
||||
}
|
||||
|
||||
|
|
@ -409,7 +409,7 @@ public static class ActivityExecutionContextExtensions
|
|||
if (outputValue == null!)
|
||||
continue;
|
||||
|
||||
var serializedOutputValue = await serializer.SerializeAsync(outputValue, cancellationToken);
|
||||
var serializedOutputValue = serializer.Serialize(outputValue, cancellationToken);
|
||||
context.JournalData[outputName] = serializedOutputValue;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,62 +31,100 @@ public class JsonWorkflowStateSerializer : ConfigurableSerializer, IWorkflowStat
|
|||
|
||||
/// <inheritdoc />
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version Serialize instead.")]
|
||||
public Task<string> SerializeAsync(WorkflowState workflowState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return Task.FromResult(JsonSerializer.Serialize(workflowState, options));
|
||||
return Task.FromResult(Serialize(workflowState, cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version SerializeToUtfBytes instead.")]
|
||||
public Task<byte[]> SerializeToUtfBytesAsync(WorkflowState workflowState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return Task.FromResult(JsonSerializer.SerializeToUtf8Bytes(workflowState, options));
|
||||
return Task.FromResult(SerializeToUtfBytes(workflowState, cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version SerializeToElement instead.")]
|
||||
public Task<JsonElement> SerializeToElementAsync(WorkflowState workflowState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return Task.FromResult(JsonSerializer.SerializeToElement(workflowState, options));
|
||||
return Task.FromResult(SerializeToElement(workflowState, cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")]
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The serialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version Serialize instead.")]
|
||||
public Task<string> SerializeAsync(object workflowState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
var json = JsonSerializer.Serialize(workflowState, workflowState.GetType(), options);
|
||||
return Task.FromResult(json);
|
||||
return Task.FromResult(Serialize(workflowState, cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version Deserialize instead.")]
|
||||
public Task<WorkflowState> DeserializeAsync(string serializedState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
var workflowState = JsonSerializer.Deserialize<WorkflowState>(serializedState, options)!;
|
||||
return Task.FromResult(workflowState);
|
||||
return Task.FromResult(Deserialize(serializedState, cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version Deserialize instead.")]
|
||||
public Task<WorkflowState> DeserializeAsync(JsonElement serializedState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
var workflowState = serializedState.Deserialize<WorkflowState>(options)!;
|
||||
return Task.FromResult(workflowState);
|
||||
return Task.FromResult(Deserialize(serializedState, cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")]
|
||||
[Obsolete("Use the non-async version Deserialize instead.")]
|
||||
public Task<T> DeserializeAsync<T>(string serializedState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.FromResult(Deserialize<T>(serializedState, cancellationToken));
|
||||
}
|
||||
|
||||
public string Serialize(WorkflowState workflowState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
var workflowState = JsonSerializer.Deserialize<T>(serializedState, options)!;
|
||||
return Task.FromResult(workflowState);
|
||||
return JsonSerializer.Serialize(workflowState, options);
|
||||
}
|
||||
|
||||
public byte[] SerializeToUtfBytes(WorkflowState workflowState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return JsonSerializer.SerializeToUtf8Bytes(workflowState, options);
|
||||
}
|
||||
|
||||
public JsonElement SerializeToElement(WorkflowState workflowState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return JsonSerializer.SerializeToElement(workflowState, options);
|
||||
}
|
||||
|
||||
public string Serialize(object workflowState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return JsonSerializer.Serialize(workflowState, workflowState.GetType(), options);
|
||||
}
|
||||
|
||||
public WorkflowState Deserialize(string serializedState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return JsonSerializer.Deserialize<WorkflowState>(serializedState, options)!;
|
||||
}
|
||||
|
||||
public WorkflowState Deserialize(JsonElement serializedState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return serializedState.Deserialize<WorkflowState>(options)!;
|
||||
}
|
||||
|
||||
public T Deserialize<T>(string serializedState, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return JsonSerializer.Deserialize<T>(serializedState, options)!;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
|
|
@ -22,39 +22,59 @@ public class SafeSerializer : ConfigurableSerializer, ISafeSerializer
|
|||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
public ValueTask<string> SerializeAsync(object? value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return ValueTask.FromResult(JsonSerializer.Serialize(value, options));
|
||||
return ValueTask.FromResult(Serialize(value, cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
public ValueTask<JsonElement> SerializeToElementAsync(object? value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return new(JsonSerializer.SerializeToElement(value, options));
|
||||
return new(SerializeToElement(value, cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
public ValueTask<T> DeserializeAsync<T>(string json, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return new(JsonSerializer.Deserialize<T>(json, options)!);
|
||||
return new(Deserialize<T>(json, cancellationToken));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[RequiresUnreferencedCode("The type T may be trimmed.")]
|
||||
public ValueTask<T> DeserializeAsync<T>(JsonElement element, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return new(Deserialize<T>(element, cancellationToken));
|
||||
}
|
||||
|
||||
public string Serialize(object? value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return new(element.Deserialize<T>(options)!);
|
||||
return JsonSerializer.Serialize(value, options);
|
||||
}
|
||||
|
||||
public JsonElement SerializeToElement(object? value, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return JsonSerializer.SerializeToElement(value, options);
|
||||
}
|
||||
|
||||
public T Deserialize<T>(string json, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return JsonSerializer.Deserialize<T>(json, options)!;
|
||||
}
|
||||
|
||||
public T Deserialize<T>(JsonElement element, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var options = GetOptions();
|
||||
return element.Deserialize<T>(options)!;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void AddConverters(JsonSerializerOptions options)
|
||||
{
|
||||
var expressionDescriptorRegistry = ServiceProvider.GetRequiredService<IExpressionDescriptorRegistry>();
|
||||
|
||||
|
||||
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
|
||||
options.Converters.Add(new TypeJsonConverter(WellKnownTypeRegistry.CreateDefault()));
|
||||
options.Converters.Add(new SafeValueConverterFactory());
|
||||
|
|
|
|||
|
|
@ -32,17 +32,17 @@ public class SerializerUnicodeEncodingTests(ITestOutputHelper testOutputHelper)
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestSafeSerializer()
|
||||
public void TestSafeSerializer()
|
||||
{
|
||||
var serializer = _serviceProvider.GetRequiredService<ISafeSerializer>();
|
||||
await TestSerializerAsync(input => serializer.SerializeAsync(input).AsTask());
|
||||
TestSerializer(input => serializer.Serialize(input));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestWorkflowStateSerializer()
|
||||
public void TestWorkflowStateSerializer()
|
||||
{
|
||||
var serializer = _serviceProvider.GetRequiredService<IWorkflowStateSerializer>();
|
||||
await TestSerializerAsync(input => serializer.SerializeAsync(input));
|
||||
TestSerializer(input => serializer.Serialize(input));
|
||||
}
|
||||
|
||||
private void TestSerializer(Func<object, string> serialize)
|
||||
|
|
@ -56,18 +56,6 @@ public class SerializerUnicodeEncodingTests(ITestOutputHelper testOutputHelper)
|
|||
var serializedStringValue = GetSerializedTextValue(serializedJson);
|
||||
Assert.Equal(unicodeString, serializedStringValue);
|
||||
}
|
||||
|
||||
private async Task TestSerializerAsync(Func<object, Task<string>> serialize)
|
||||
{
|
||||
var unicodeString = UnicodeRangeGenerator.GenerateUnicodeString();
|
||||
var anonymousObject = new
|
||||
{
|
||||
Text = unicodeString
|
||||
};
|
||||
var serializedJson = await serialize(anonymousObject);
|
||||
var serializedStringValue = GetSerializedTextValue(serializedJson);
|
||||
Assert.Equal(unicodeString, serializedStringValue);
|
||||
}
|
||||
|
||||
private string GetSerializedTextValue(string serializedJson)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue