Addresses warnings and enforces null safety (#7051)
* Enhance null-safety annotations across modules and refactor for improved consistency: - Added `null!` annotations to enforce non-nullability expectations. - Updated workflows, tests, and runtime services to handle default null values reliably. - Removed obsolete and unused APIs, simplifying interfaces and improving maintainability. - Refactored methods and properties for clarity, thread-safety, and consistency. - Adjusted test configurations for code coverage tracking and integration improvements. * Refactor activity iteration in container serialization tests to simplify type casting.
This commit is contained in:
parent
490c8a2c9e
commit
2c0b3da5de
|
|
@ -160,7 +160,7 @@ public static class JsonObjectExtensions
|
|||
{
|
||||
return model.GetProperty<T>(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ public interface ICommandSender
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <typeparam name="T">The type of the result.</typeparam>
|
||||
/// <returns>The result.</returns>
|
||||
Task<T> SendAsync<T>(ICommand<T> command, ICommandStrategy strategy, CancellationToken cancellationToken = default);
|
||||
Task<T> SendAsync<T>(ICommand<T> command, ICommandStrategy? strategy, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a command using the specified strategy.
|
||||
|
|
@ -39,7 +39,7 @@ public interface ICommandSender
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <typeparam name="T">The type of the result.</typeparam>
|
||||
/// <returns>The result.</returns>
|
||||
Task<T> SendAsync<T>(ICommand<T> command, ICommandStrategy strategy, IDictionary<object, object> headers, CancellationToken cancellationToken = default);
|
||||
Task<T> SendAsync<T>(ICommand<T> command, ICommandStrategy? strategy, IDictionary<object, object> headers, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a command using the default strategy.
|
||||
|
|
@ -54,7 +54,7 @@ public interface ICommandSender
|
|||
/// <param name="command">The command to send.</param>
|
||||
/// <param name="strategy">The command strategy to use.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
Task SendAsync(ICommand command, ICommandStrategy strategy, CancellationToken cancellationToken = default);
|
||||
Task SendAsync(ICommand command, ICommandStrategy? strategy, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Sends a command using the specified strategy.
|
||||
|
|
@ -63,5 +63,5 @@ public interface ICommandSender
|
|||
/// <param name="strategy">The command strategy to use.</param>
|
||||
/// <param name="headers">Any headers to pass along.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
Task SendAsync(ICommand command, ICommandStrategy strategy, IDictionary<object, object> headers, CancellationToken cancellationToken = default);
|
||||
Task SendAsync(ICommand command, ICommandStrategy? strategy, IDictionary<object, object> headers, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -39,7 +39,7 @@ public static class MediatorExtensions
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
public static async Task SendAsync(this IMediator mediator, ICommand command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await mediator.SendAsync(command, default, cancellationToken);
|
||||
await mediator.SendAsync(command, null, cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -50,6 +50,6 @@ public static class MediatorExtensions
|
|||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
public static async Task SendAsync(this ICommandSender commandSender, ICommand command, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await commandSender.SendAsync(command, default, cancellationToken);
|
||||
await commandSender.SendAsync(command, null, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
@ -54,9 +54,10 @@ public class DefaultMediator : IMediator
|
|||
return (T)context.Response;
|
||||
}
|
||||
|
||||
public async Task<T> SendAsync<T>(ICommand<T> command, ICommandStrategy strategy, IDictionary<object, object> headers, CancellationToken cancellationToken = default)
|
||||
public async Task<T> SendAsync<T>(ICommand<T> command, ICommandStrategy? strategy, IDictionary<object, object> headers, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var resultType = typeof(T);
|
||||
strategy ??= _defaultCommandStrategy;
|
||||
var context = new CommandContext(command, strategy, resultType, headers, _serviceProvider, cancellationToken);
|
||||
await _commandPipeline.InvokeAsync(context);
|
||||
|
||||
|
|
@ -92,7 +93,7 @@ public class DefaultMediator : IMediator
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T> SendAsync<T>(ICommand<T> command, ICommandStrategy strategy, CancellationToken cancellationToken = default)
|
||||
public Task<T> SendAsync<T>(ICommand<T> command, ICommandStrategy? strategy, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return SendAsync(command, strategy, new Dictionary<object, object>(), cancellationToken);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public static class DispatchWorkflowExtensions
|
|||
var workflowDispatcher = serviceProvider.GetRequiredService<IWorkflowDispatcher>();
|
||||
var dispatchWorkflowResponse = await workflowDispatcher.DispatchAsync(new DispatchWorkflowDefinitionRequest
|
||||
{
|
||||
DefinitionVersionId = workflow.DefinitionHandle.DefinitionVersionId,
|
||||
DefinitionVersionId = workflow.DefinitionHandle.DefinitionVersionId!,
|
||||
InstanceId = instanceId ?? Guid.NewGuid().ToString(),
|
||||
});
|
||||
dispatchWorkflowResponse.ThrowIfFailed();
|
||||
|
|
|
|||
|
|
@ -3,33 +3,24 @@ using Xunit.Abstractions;
|
|||
|
||||
namespace Elsa.Testing.Shared;
|
||||
|
||||
public class XunitLogger : ILogger
|
||||
public class XunitLogger(ITestOutputHelper testOutputHelper, string categoryName) : ILogger
|
||||
{
|
||||
private readonly ITestOutputHelper _testOutputHelper;
|
||||
private readonly string _categoryName;
|
||||
|
||||
public XunitLogger(ITestOutputHelper testOutputHelper, string categoryName)
|
||||
{
|
||||
_testOutputHelper = testOutputHelper;
|
||||
_categoryName = categoryName;
|
||||
}
|
||||
|
||||
public IDisposable BeginScope<TState>(TState state) => NoopDisposable.Instance;
|
||||
public IDisposable BeginScope<TState>(TState state) where TState : notnull => NoopDisposable.Instance;
|
||||
|
||||
public bool IsEnabled(LogLevel logLevel)
|
||||
=> true;
|
||||
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
|
||||
{
|
||||
_testOutputHelper.WriteLine($"{_categoryName} [{eventId}] {formatter(state, exception)}");
|
||||
testOutputHelper.WriteLine($"{categoryName} [{eventId}] {formatter(state, exception)}");
|
||||
|
||||
if (exception != null)
|
||||
_testOutputHelper.WriteLine(exception.ToString());
|
||||
testOutputHelper.WriteLine(exception.ToString());
|
||||
}
|
||||
|
||||
private class NoopDisposable : IDisposable
|
||||
{
|
||||
public static readonly NoopDisposable Instance = new NoopDisposable();
|
||||
public static readonly NoopDisposable Instance = new();
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,16 +2,9 @@
|
|||
|
||||
namespace Elsa.Expressions.Liquid.Helpers;
|
||||
|
||||
public class ConfigurationSectionWrapper
|
||||
public class ConfigurationSectionWrapper(IConfigurationSection section)
|
||||
{
|
||||
private readonly IConfigurationSection _section;
|
||||
public override string ToString() => section.Value!;
|
||||
|
||||
public ConfigurationSectionWrapper(IConfigurationSection section)
|
||||
{
|
||||
_section = section;
|
||||
}
|
||||
|
||||
public override string ToString() => _section.Value;
|
||||
|
||||
public ConfigurationSectionWrapper GetSection(string name) => new(_section.GetSection(name));
|
||||
public ConfigurationSectionWrapper GetSection(string name) => new(section.GetSection(name));
|
||||
}
|
||||
|
|
@ -461,7 +461,7 @@ public class HttpEndpoint : Trigger<HttpRequest>
|
|||
var contentType = httpRequest.ContentType!;
|
||||
var headers = httpRequest.Headers.ToDictionary(x => x.Key, x => x.Value.ToArray());
|
||||
|
||||
return await context.ParseContentAsync(contentStream, contentType, targetType, headers, cancellationToken);
|
||||
return await context.ParseContentAsync(contentStream, contentType, targetType, headers!, cancellationToken);
|
||||
}
|
||||
|
||||
private static bool HasContent(HttpRequest httpRequest) => httpRequest.Headers.ContentLength > 0;
|
||||
|
|
|
|||
|
|
@ -240,8 +240,8 @@ public abstract class SendHttpRequestBase(string? source = null, int? line = nul
|
|||
_ => typeof(string)
|
||||
};
|
||||
|
||||
var contentHeadersDictionary = contentHeaders.ToDictionary(x => x.Key, x => x.Value.Cast<string?>().ToArray(), StringComparer.OrdinalIgnoreCase);
|
||||
var responseHeadersDictionary = responseHeaders.ToDictionary(x => x.Key, x => x.Value.Cast<string?>().ToArray(), StringComparer.OrdinalIgnoreCase);
|
||||
var contentHeadersDictionary = contentHeaders.ToDictionary(x => x.Key, x => x.Value.ToArray(), StringComparer.OrdinalIgnoreCase);
|
||||
var responseHeadersDictionary = responseHeaders.ToDictionary(x => x.Key, x => x.Value.ToArray(), StringComparer.OrdinalIgnoreCase);
|
||||
var headersDictionary = contentHeadersDictionary.Concat(responseHeadersDictionary).ToDictionary(x => x.Key, x => x.Value, StringComparer.OrdinalIgnoreCase);
|
||||
return await context.ParseContentAsync(contentStream, contentType, targetType, headersDictionary, cancellationToken);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ public class WriteHttpResponse : Activity
|
|||
// Add headers.
|
||||
var headers = context.GetHeaders(ResponseHeaders);
|
||||
foreach (var header in headers)
|
||||
response.Headers.Add(header.Key, header.Value);
|
||||
response.Headers[header.Key] = header.Value;
|
||||
|
||||
// Get content and content type.
|
||||
var content = context.Get(Content);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public class FormUrlEncodedHttpContentFactory : IHttpContentFactory
|
|||
return dictionary.ToDictionary(x => x.Key, x => x.Value.ToString() ?? string.Empty);
|
||||
|
||||
if (content is string or JsonObject)
|
||||
return JsonSerializer.Deserialize<Dictionary<string, string>>(JsonSerializer.Serialize(content));
|
||||
return JsonSerializer.Deserialize<Dictionary<string, string>>(JsonSerializer.Serialize(content))!;
|
||||
|
||||
var jsonElement = JsonSerializer.SerializeToElement(content);
|
||||
return jsonElement.EnumerateObject().ToDictionary(x => x.Name, x => x.Value.ToString());
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace Elsa.Extensions;
|
|||
|
||||
internal static class HttpActivityExecutionContextExtensions
|
||||
{
|
||||
public static async Task<object?> ParseContentAsync(this ActivityExecutionContext context, Stream content, string contentType, Type? returnType, Dictionary<string, string?[]> headers, CancellationToken cancellationToken)
|
||||
public static async Task<object?> ParseContentAsync(this ActivityExecutionContext context, Stream content, string contentType, Type? returnType, Dictionary<string, string[]> headers, CancellationToken cancellationToken)
|
||||
{
|
||||
var parsers = context.GetServices<IHttpContentParser>().OrderByDescending(x => x.Priority).ToList();
|
||||
var httpResponseParserContext = new HttpResponseParserContext(content, contentType, returnType, headers, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using Elsa.Http.Options;
|
||||
using Elsa.Mediator.Contracts;
|
||||
using Elsa.Mediator.Contracts;
|
||||
using Elsa.Workflows.Runtime.Notifications;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Elsa.Http.Handlers;
|
||||
|
||||
|
|
@ -10,7 +8,7 @@ namespace Elsa.Http.Handlers;
|
|||
/// A handler that updates the route table when workflow triggers and bookmarks are indexed.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class UpdateRouteTable(IRouteTableUpdater routeTableUpdater, IOptions<HttpActivityOptions> options) :
|
||||
public class UpdateRouteTable(IRouteTableUpdater routeTableUpdater) :
|
||||
INotificationHandler<WorkflowTriggersIndexed>,
|
||||
INotificationHandler<WorkflowBookmarksIndexed>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ public static class BulkUpsertExtensions
|
|||
var paramName = $"{{{parameterCount++}}}";
|
||||
|
||||
// If it's a shadow property, retrieve value via Entry(..).Property(..)
|
||||
object? value = property.IsShadowProperty()
|
||||
var value = property.IsShadowProperty()
|
||||
? dbContext.Entry(entity).Property(property.Name).CurrentValue
|
||||
: property.PropertyInfo?.GetValue(entity);
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ public static class BulkUpsertExtensions
|
|||
{
|
||||
var paramName = $"{{{parameterCount++}}}";
|
||||
|
||||
object? value = property.IsShadowProperty()
|
||||
var value = property.IsShadowProperty()
|
||||
? dbContext.Entry(entity).Property(property.Name).CurrentValue
|
||||
: property.PropertyInfo?.GetValue(entity);
|
||||
|
||||
|
|
@ -185,7 +185,7 @@ public static class BulkUpsertExtensions
|
|||
value = converter.ConvertToProvider(value);
|
||||
|
||||
placeholders.Add(paramName);
|
||||
parameters.Add(value);
|
||||
parameters.Add(value!);
|
||||
}
|
||||
|
||||
sb.Append($"({string.Join(", ", placeholders)})");
|
||||
|
|
@ -238,7 +238,7 @@ public static class BulkUpsertExtensions
|
|||
{
|
||||
var paramName = $"{{{parameterCount++}}}";
|
||||
|
||||
object? value = property.IsShadowProperty()
|
||||
var value = property.IsShadowProperty()
|
||||
? dbContext.Entry(entity).Property(property.Name).CurrentValue
|
||||
: property.PropertyInfo?.GetValue(entity);
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ public static class BulkUpsertExtensions
|
|||
else
|
||||
placeholders.Add(paramName);
|
||||
|
||||
parameters.Add(value);
|
||||
parameters.Add(value!);
|
||||
}
|
||||
|
||||
sb.Append($"({string.Join(", ", placeholders)})");
|
||||
|
|
@ -308,7 +308,7 @@ public static class BulkUpsertExtensions
|
|||
{
|
||||
var paramName = $"{{{parameterCount++}}}";
|
||||
|
||||
object? value = property.IsShadowProperty()
|
||||
var value = property.IsShadowProperty()
|
||||
? dbContext.Entry(entity).Property(property.Name).CurrentValue
|
||||
: property.PropertyInfo?.GetValue(entity);
|
||||
|
||||
|
|
@ -317,7 +317,7 @@ public static class BulkUpsertExtensions
|
|||
value = converter.ConvertToProvider(value);
|
||||
|
||||
placeholders.Add(paramName);
|
||||
parameters.Add(value);
|
||||
parameters.Add(value!);
|
||||
}
|
||||
|
||||
sb.Append($"({string.Join(", ", placeholders)})");
|
||||
|
|
@ -374,7 +374,7 @@ public static class BulkUpsertExtensions
|
|||
{
|
||||
var paramName = $"{{{parameterCount++}}}";
|
||||
|
||||
object? value = property.IsShadowProperty()
|
||||
var value = property.IsShadowProperty()
|
||||
? dbContext.Entry(entity).Property(property.Name).CurrentValue
|
||||
: property.PropertyInfo?.GetValue(entity);
|
||||
|
||||
|
|
@ -382,7 +382,7 @@ public static class BulkUpsertExtensions
|
|||
if (converter != null)
|
||||
value = converter.ConvertToProvider(value);
|
||||
|
||||
parameters.Add(value);
|
||||
parameters.Add(value!);
|
||||
|
||||
// Oracle aliases must match the column name
|
||||
var alias = property.GetColumnName(storeObject);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ namespace Elsa.Persistence.EFCore;
|
|||
/// For plain objects, fall back to deep equality comparison using JSON serialization
|
||||
/// (safe, but inefficient).
|
||||
/// </remarks>
|
||||
public class JsonValueComparer<T> : ValueComparer<T> {
|
||||
public class JsonValueComparer<T>() : ValueComparer<T>((t1, t2) => DoEquals(t1!, t2!),
|
||||
t => DoGetHashCode(t),
|
||||
t => DoGetSnapshot(t))
|
||||
{
|
||||
|
||||
private static string Json(T instance) {
|
||||
return JsonSerializer.Serialize(instance);
|
||||
|
|
@ -24,9 +27,7 @@ public class JsonValueComparer<T> : ValueComparer<T> {
|
|||
if (instance is ICloneable cloneable)
|
||||
return (T)cloneable.Clone();
|
||||
|
||||
var result = (T)JsonSerializer.Deserialize<T>(Json(instance));
|
||||
return result;
|
||||
|
||||
return JsonSerializer.Deserialize<T>(Json(instance))!;
|
||||
}
|
||||
|
||||
private static int DoGetHashCode(T instance) {
|
||||
|
|
@ -43,15 +44,6 @@ public class JsonValueComparer<T> : ValueComparer<T> {
|
|||
if (left is IEquatable<T> equatable)
|
||||
return equatable.Equals(right);
|
||||
|
||||
var result = Json(left).Equals(Json(right));
|
||||
return result;
|
||||
|
||||
return Json(left).Equals(Json(right));
|
||||
}
|
||||
|
||||
public JsonValueComparer() : base(
|
||||
(t1, t2) => DoEquals(t1, t2),
|
||||
t => DoGetHashCode(t),
|
||||
t => DoGetSnapshot(t)) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ internal static class JsonValueConverterHelper
|
|||
|
||||
public static string Serialize<T>(T obj) where T : class
|
||||
{
|
||||
return (obj == null ? null : JsonSerializer.Serialize(obj, JsonSerializerOptions))!;
|
||||
return (obj == null! ? null : JsonSerializer.Serialize(obj, JsonSerializerOptions))!;
|
||||
}
|
||||
|
||||
private static JsonSerializerOptions CreateJsonSerializerOptions()
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ public class EFCoreWorkflowDefinitionStore(EntityStore<ManagementElsaDbContext,
|
|||
if (filter.IsSystem != null)
|
||||
queryable = filter.IsSystem == true
|
||||
? queryable.Where(x => x.IsSystem == true)
|
||||
: queryable.Where(x => x.IsSystem == false || x.IsSystem == null);
|
||||
: queryable.Where(x => x.IsSystem == false || x.IsSystem == null!);
|
||||
|
||||
if (filter.IsReadonly != null) queryable = queryable.Where(x => x.IsReadonly == filter.IsReadonly);
|
||||
return queryable;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using Elsa.Common.Codecs;
|
|||
using Elsa.Common.Entities;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows;
|
||||
using Elsa.Workflows.Management.Options;
|
||||
using Elsa.Workflows.Runtime;
|
||||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Extensions;
|
||||
|
|
@ -15,7 +14,6 @@ using Elsa.Workflows.Runtime.OrderDefinitions;
|
|||
using Elsa.Workflows.State;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Open.Linq.AsyncExtensions;
|
||||
|
||||
namespace Elsa.Persistence.EFCore.Modules.Runtime;
|
||||
|
|
@ -26,10 +24,8 @@ namespace Elsa.Persistence.EFCore.Modules.Runtime;
|
|||
[UsedImplicitly]
|
||||
public class EFCoreActivityExecutionStore(
|
||||
EntityStore<RuntimeElsaDbContext, ActivityExecutionRecord> store,
|
||||
ISafeSerializer safeSerializer,
|
||||
IPayloadSerializer payloadSerializer,
|
||||
ICompressionCodecResolver compressionCodecResolver,
|
||||
IOptions<ManagementOptions> options) : IActivityExecutionStore
|
||||
ICompressionCodecResolver compressionCodecResolver) : IActivityExecutionStore
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task SaveAsync(ActivityExecutionRecord record, CancellationToken cancellationToken = default) => await store.SaveAsync(record, OnSaveAsync, cancellationToken);
|
||||
|
|
|
|||
|
|
@ -48,13 +48,14 @@ internal class Export : ElsaEndpoint<Request>
|
|||
{
|
||||
if (request.DefinitionId != null)
|
||||
await DownloadSingleWorkflowAsync(request.DefinitionId, request.VersionOptions, cancellationToken);
|
||||
else
|
||||
else if (request.Ids != null)
|
||||
await DownloadMultipleWorkflowsAsync(request.Ids, cancellationToken);
|
||||
else await Send.NoContentAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private async Task DownloadMultipleWorkflowsAsync(ICollection<string> ids, CancellationToken cancellationToken)
|
||||
{
|
||||
List<WorkflowDefinition> definitions = (await _store.FindManyAsync(new WorkflowDefinitionFilter
|
||||
List<WorkflowDefinition> definitions = (await _store.FindManyAsync(new()
|
||||
{
|
||||
Ids = ids
|
||||
}, cancellationToken)).ToList();
|
||||
|
|
@ -88,7 +89,7 @@ internal class Export : ElsaEndpoint<Request>
|
|||
private async Task DownloadSingleWorkflowAsync(string definitionId, string? versionOptions, CancellationToken cancellationToken)
|
||||
{
|
||||
var parsedVersionOptions = string.IsNullOrEmpty(versionOptions) ? VersionOptions.Latest : VersionOptions.FromString(versionOptions);
|
||||
WorkflowDefinition? definition = (await _store.FindManyAsync(new WorkflowDefinitionFilter
|
||||
WorkflowDefinition? definition = (await _store.FindManyAsync(new()
|
||||
{
|
||||
DefinitionId = definitionId,
|
||||
VersionOptions = parsedVersionOptions
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ internal class List(IWorkflowInstanceStore store) : ElsaEndpoint<Request, Respon
|
|||
{
|
||||
var o = new WorkflowInstanceOrder<string>
|
||||
{
|
||||
KeySelector = p => p.Name,
|
||||
KeySelector = p => p.Name!,
|
||||
Direction = direction
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -26,18 +26,19 @@ public class NotReadOnlyRequirementHandler : AuthorizationHandler<NotReadOnlyReq
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, NotReadOnlyRequirement requirement, NotReadOnlyResource resource)
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, NotReadOnlyRequirement requirement, NotReadOnlyResource resource)
|
||||
{
|
||||
if (_managementOptions.Value.IsReadOnlyMode)
|
||||
{
|
||||
context.Fail(new AuthorizationFailureReason(this, "Workflow edit is not allowed when the read-only mode is enabled."));
|
||||
context.Fail(new(this, "Workflow edit is not allowed when the read-only mode is enabled."));
|
||||
}
|
||||
|
||||
if (resource.WorkflowDefinition != null && (resource.WorkflowDefinition.IsReadonly || resource.WorkflowDefinition.IsSystem))
|
||||
{
|
||||
context.Fail(new AuthorizationFailureReason(this, "Workflow edit is not allowed for a readonly or system workflow."));
|
||||
context.Fail(new(this, "Workflow edit is not allowed for a readonly or system workflow."));
|
||||
}
|
||||
|
||||
context.Succeed(requirement);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ public class ArgumentJsonConverter : JsonConverter<ArgumentDefinition>
|
|||
var typeAlias = _wellKnownTypeRegistry.TryGetAlias(typeName, out var alias) ? alias : null;
|
||||
var isArray = typeName.IsArray;
|
||||
var isCollection = typeName.IsCollectionType();
|
||||
var elementTypeName = isArray ? typeName.GetElementType() : isCollection ? typeName.GenericTypeArguments[0] : typeName;
|
||||
var elementTypeName = isArray ? typeName.GetElementType()! : isCollection ? typeName.GenericTypeArguments[0] : typeName;
|
||||
var elementTypeAlias = _wellKnownTypeRegistry.GetAliasOrDefault(elementTypeName);
|
||||
var isAliasedArray = (isArray || isCollection) && typeAlias != null;
|
||||
var finalTypeAlias = isArray || isCollection ? typeAlias ?? elementTypeAlias : elementTypeAlias;
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public class ParallelForEach<T> : Activity
|
|||
private ICollection<Guid> GetTagList(ActivityExecutionContext context, string propertyName)
|
||||
{
|
||||
// Read the list of tags from the context using the specified property name. The value is stored as JsonArray, so we need to deserialize it.
|
||||
var jsonArray = context.GetProperty<JsonArray>(propertyName);
|
||||
var jsonArray = context.GetProperty<JsonArray>(propertyName)!;
|
||||
return jsonArray.Select(x => x.ConvertTo<Guid>()).ToList();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ using Elsa.Workflows.Models;
|
|||
namespace Elsa.Workflows.Builders;
|
||||
|
||||
/// <inheritdoc />
|
||||
public class WorkflowBuilder(IActivityVisitor activityVisitor, IIdentityGraphService identityGraphService, IActivityRegistry activityRegistry, IIdentityGenerator identityGenerator)
|
||||
public class WorkflowBuilder(IActivityVisitor activityVisitor, IIdentityGraphService identityGraphService, IActivityRegistry activityRegistry)
|
||||
: IWorkflowBuilder
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
|
|
@ -402,7 +402,7 @@ public partial class WorkflowExecutionContext : IExecutionContext
|
|||
/// <summary>
|
||||
/// The expression execution context for the current workflow execution.
|
||||
/// </summary>
|
||||
public ExpressionExecutionContext? ExpressionExecutionContext { get; private set; }
|
||||
public ExpressionExecutionContext ExpressionExecutionContext { get; private set; } = null!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<Variable> Variables => Workflow.Variables;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using Elsa.Common;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Pipelines.ActivityExecution;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -19,7 +18,7 @@ public static class ExceptionHandlingMiddlewareExtensions
|
|||
/// <summary>
|
||||
/// Catches any exceptions thrown by downstream components and transitions the workflow into the faulted state.
|
||||
/// </summary>
|
||||
public class ExceptionHandlingMiddleware(ActivityMiddlewareDelegate next, IIncidentStrategyResolver incidentStrategyResolver, ISystemClock systemClock, ILogger<ExceptionHandlingMiddleware> logger)
|
||||
public class ExceptionHandlingMiddleware(ActivityMiddlewareDelegate next, IIncidentStrategyResolver incidentStrategyResolver, ILogger<ExceptionHandlingMiddleware> logger)
|
||||
: IActivityExecutionMiddleware
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using System.Reflection;
|
|||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using Elsa.Expressions.Contracts;
|
||||
using Elsa.Extensions;
|
||||
using Elsa.Workflows.Serialization.ReferenceHandlers;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
@ -14,7 +13,7 @@ namespace Elsa.Workflows.Serialization.Converters;
|
|||
/// <summary>
|
||||
/// Reads objects as primitive types rather than <see cref="JsonElement"/> values while also maintaining the .NET type name for reconstructing the actual type.
|
||||
/// </summary>
|
||||
public class PolymorphicObjectConverter(IWellKnownTypeRegistry wellKnownTypeRegistry) : JsonConverter<object>
|
||||
public class PolymorphicObjectConverter : JsonConverter<object>
|
||||
{
|
||||
private const string TypePropertyName = "_type";
|
||||
private const string ItemsPropertyName = "_items";
|
||||
|
|
@ -77,7 +76,7 @@ public class PolymorphicObjectConverter(IWellKnownTypeRegistry wellKnownTypeRegi
|
|||
{
|
||||
var parsedModel = JsonElement.ParseValue(ref reader);
|
||||
var systemTextJson = parsedModel.GetProperty(IslandPropertyName).GetString();
|
||||
return !string.IsNullOrWhiteSpace(systemTextJson) ? JsonObject.Parse(systemTextJson) : new JsonObject();
|
||||
return !string.IsNullOrWhiteSpace(systemTextJson) ? JsonNode.Parse(systemTextJson)! : new JsonObject();
|
||||
}
|
||||
|
||||
var isJsonArray = targetType == typeof(JsonArray);
|
||||
|
|
@ -86,7 +85,7 @@ public class PolymorphicObjectConverter(IWellKnownTypeRegistry wellKnownTypeRegi
|
|||
{
|
||||
var parsedModel = JsonElement.ParseValue(ref reader);
|
||||
var systemTextJson = parsedModel.GetProperty(IslandPropertyName).GetString();
|
||||
return !string.IsNullOrWhiteSpace(systemTextJson) ? JsonArray.Parse(systemTextJson) : new JsonArray();
|
||||
return !string.IsNullOrWhiteSpace(systemTextJson) ? JsonNode.Parse(systemTextJson)! : new JsonArray();
|
||||
}
|
||||
|
||||
var isDictionary = typeof(IDictionary).IsAssignableFrom(targetType);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,6 @@ public class PolymorphicObjectConverterFactory : JsonConverterFactory
|
|||
if (typeof(IDictionary<string, object>).IsAssignableFrom(typeToConvert))
|
||||
return new PolymorphicDictionaryConverter(options, _wellKnownTypeRegistry);
|
||||
|
||||
return new PolymorphicObjectConverter(_wellKnownTypeRegistry);
|
||||
return new PolymorphicObjectConverter();
|
||||
}
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ public class WorkflowInstanceStorageDriver(IPayloadSerializer payloadSerializer,
|
|||
try
|
||||
{
|
||||
var node = JsonSerializer.SerializeToNode(value);
|
||||
dictionary[id] = node;
|
||||
dictionary[id] = node!;
|
||||
}
|
||||
catch (Exception ex) when (ex is JsonException or NotSupportedException or ObjectDisposedException)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -125,6 +125,13 @@ public class WorkflowDefinitionActivity : Composite, IInitializable
|
|||
var serviceProvider = context.GetRequiredService<IServiceProvider>();
|
||||
var activityDescriptor = await FindActivityDescriptorAsync(serviceProvider);
|
||||
|
||||
if (activityDescriptor == null)
|
||||
{
|
||||
var logger = serviceProvider.GetRequiredService<ILogger<WorkflowDefinitionActivity>>();
|
||||
logger.LogWarning("Could not find activity descriptor for activity type {ActivityType}", Type);
|
||||
return;
|
||||
}
|
||||
|
||||
DeclareInputAsVariables(activityDescriptor, (descriptor, variable) =>
|
||||
{
|
||||
var inputName = descriptor.Name;
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ public class VariableDefinitionMapper(IWellKnownTypeRegistry wellKnownTypeRegist
|
|||
|
||||
var isArray = valueType.IsArray;
|
||||
var isCollection = valueType.IsCollectionType();
|
||||
var elementValueType = isArray ? valueType.GetElementType() : isCollection ? valueType.GenericTypeArguments[0] : valueType;
|
||||
var elementValueType = isArray ? valueType.GetElementType()! : isCollection ? valueType.GenericTypeArguments[0] : valueType;
|
||||
var elementTypeAlias = wellKnownTypeRegistry.GetAliasOrDefault(elementValueType);
|
||||
|
||||
return new(source.Id, source.Name, elementTypeAlias, isArray, serializedValue, storageDriverTypeName);
|
||||
|
|
|
|||
|
|
@ -11,20 +11,20 @@ public interface IWorkflowDispatcher
|
|||
/// <summary>
|
||||
/// Dispatches a request to execute the specified workflow definition.
|
||||
/// </summary>
|
||||
Task<DispatchWorkflowResponse> DispatchAsync(DispatchWorkflowDefinitionRequest request, DispatchWorkflowOptions options, CancellationToken cancellationToken = default);
|
||||
Task<DispatchWorkflowResponse> DispatchAsync(DispatchWorkflowDefinitionRequest request, DispatchWorkflowOptions? options, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Dispatches a request to execute the specified workflow instance.
|
||||
/// </summary>
|
||||
Task<DispatchWorkflowResponse> DispatchAsync(DispatchWorkflowInstanceRequest request, DispatchWorkflowOptions options, CancellationToken cancellationToken = default);
|
||||
Task<DispatchWorkflowResponse> DispatchAsync(DispatchWorkflowInstanceRequest request, DispatchWorkflowOptions? options, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Starts all workflows and resumes existing workflow instances based on the specified activity type and bookmark payload.
|
||||
/// </summary>
|
||||
Task<DispatchWorkflowResponse> DispatchAsync(DispatchTriggerWorkflowsRequest request, DispatchWorkflowOptions options, CancellationToken cancellationToken = default);
|
||||
Task<DispatchWorkflowResponse> DispatchAsync(DispatchTriggerWorkflowsRequest request, DispatchWorkflowOptions? options, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Resumes the workflow waiting for the specified bookmark.
|
||||
/// </summary>
|
||||
Task<DispatchWorkflowResponse> DispatchAsync(DispatchResumeWorkflowsRequest request, DispatchWorkflowOptions options, CancellationToken cancellationToken = default);
|
||||
Task<DispatchWorkflowResponse> DispatchAsync(DispatchResumeWorkflowsRequest request, DispatchWorkflowOptions? options, CancellationToken cancellationToken = default);
|
||||
}
|
||||
|
|
@ -15,11 +15,6 @@ public interface IWorkflowExecutionLogStore : ILogRecordStore<WorkflowExecutionL
|
|||
/// </summary>
|
||||
Task AddAsync(WorkflowExecutionLogRecord record, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds the specified set of <see cref="WorkflowExecutionLogRecord"/> objects to te persistence store.
|
||||
/// </summary>
|
||||
Task AddManyAsync(IEnumerable<WorkflowExecutionLogRecord> records, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Adds or updates the specified <see cref="WorkflowExecutionLogRecord"/> in the persistence store.
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ using Elsa.Workflows.Runtime.Entities;
|
|||
using Elsa.Workflows.Runtime.Handlers;
|
||||
using Elsa.Workflows.Runtime.Options;
|
||||
using Elsa.Workflows.Runtime.Providers;
|
||||
using Elsa.Workflows.Runtime.Services;
|
||||
using Elsa.Workflows.Runtime.Stores;
|
||||
using Elsa.Workflows.Runtime.Tasks;
|
||||
using Elsa.Workflows.Runtime.UIHints;
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public class TriggerFilter
|
|||
if (WorkflowDefinitionVersionId != null) queryable = queryable.Where(x => x.WorkflowDefinitionVersionId == WorkflowDefinitionVersionId);
|
||||
if (WorkflowDefinitionVersionIds != null) queryable = queryable.Where(x => WorkflowDefinitionVersionIds.Contains(x.WorkflowDefinitionVersionId));
|
||||
if (Name != null) queryable = queryable.Where(x => x.Name == Name);
|
||||
if (Names != null) queryable = queryable.Where(x => Names.Contains(x.Name));
|
||||
if (Names != null) queryable = queryable.Where(x => Names.Contains(x.Name!));
|
||||
if (Hash != null) queryable = queryable.Where(x => x.Hash == Hash);
|
||||
return queryable;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using Elsa.Workflows.Notifications;
|
|||
using Elsa.Workflows.Runtime.Activities;
|
||||
using Elsa.Workflows.Runtime.Stimuli;
|
||||
using JetBrains.Annotations;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Handlers;
|
||||
|
||||
|
|
@ -12,7 +11,7 @@ namespace Elsa.Workflows.Runtime.Handlers;
|
|||
/// Resumes any blocking <see cref="DispatchWorkflow"/> activities when its child workflow completes.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
internal class ResumeDispatchWorkflowActivity(IBookmarkQueue bookmarkQueue, IStimulusHasher stimulusHasher, ILogger<ResumeDispatchWorkflowActivity> logger) : INotificationHandler<WorkflowExecuted>
|
||||
internal class ResumeDispatchWorkflowActivity(IBookmarkQueue bookmarkQueue, IStimulusHasher stimulusHasher) : INotificationHandler<WorkflowExecuted>
|
||||
{
|
||||
private static readonly string ActivityTypeName = ActivityTypeNameHelper.GenerateTypeName<DispatchWorkflow>();
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ public class ObsoleteWorkflowRuntime(
|
|||
TriggerActivityId = options?.TriggerActivityId
|
||||
};
|
||||
var response = await client.CreateAndRunInstanceAsync(createRequest, cancellationToken);
|
||||
return new(response.WorkflowInstanceId, response.Status, response.SubStatus, response.Bookmarks, response.Incidents, null, null);
|
||||
return new(response.WorkflowInstanceId, response.Status, response.SubStatus, response.Bookmarks, response.Incidents, null, new Dictionary<string, object>());
|
||||
}
|
||||
|
||||
public async Task<ICollection<WorkflowExecutionResult>> StartWorkflowsAsync(string activityTypeName, object bookmarkPayload, TriggerWorkflowsOptions? options = null)
|
||||
|
|
@ -82,7 +82,7 @@ public class ObsoleteWorkflowRuntime(
|
|||
Input = options?.Input
|
||||
};
|
||||
var result = await stimulusSender.SendAsync(activityTypeName, bookmarkPayload, metadata, cancellationToken);
|
||||
var results = result.WorkflowInstanceResponses.Select(x => new WorkflowExecutionResult(x.WorkflowInstanceId, x.Status, x.SubStatus, x.Bookmarks, x.Incidents, null, null)).ToList();
|
||||
var results = result.WorkflowInstanceResponses.Select(x => new WorkflowExecutionResult(x.WorkflowInstanceId, x.Status, x.SubStatus, x.Bookmarks, x.Incidents, null, new Dictionary<string, object>())).ToList();
|
||||
return results;
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ public class ObsoleteWorkflowRuntime(
|
|||
|
||||
var response = await workflowClient.RunInstanceAsync(runWorkflowRequest, cancellationToken);
|
||||
|
||||
return new(response.WorkflowInstanceId, response.Status, response.SubStatus, response.Bookmarks, response.Incidents,null, null);
|
||||
return new(response.WorkflowInstanceId, response.Status, response.SubStatus, response.Bookmarks, response.Incidents,null, new Dictionary<string, object>());
|
||||
}
|
||||
|
||||
public async Task<ICollection<WorkflowExecutionResult>> ResumeWorkflowsAsync(string activityTypeName, object bookmarkPayload, TriggerWorkflowsOptions? options = null)
|
||||
|
|
@ -125,7 +125,7 @@ public class ObsoleteWorkflowRuntime(
|
|||
Input = options?.Input
|
||||
};
|
||||
var result = await stimulusSender.SendAsync(activityTypeName, bookmarkPayload, metadata, cancellationToken);
|
||||
var results = result.WorkflowInstanceResponses.Select(x => new WorkflowExecutionResult(x.WorkflowInstanceId, x.Status, x.SubStatus, x.Bookmarks, x.Incidents, null, null)).ToList();
|
||||
var results = result.WorkflowInstanceResponses.Select(x => new WorkflowExecutionResult(x.WorkflowInstanceId, x.Status, x.SubStatus, x.Bookmarks, x.Incidents, null, new Dictionary<string, object>())).ToList();
|
||||
return results;
|
||||
}
|
||||
|
||||
|
|
@ -141,7 +141,7 @@ public class ObsoleteWorkflowRuntime(
|
|||
Input = options?.Input
|
||||
};
|
||||
var result = await stimulusSender.SendAsync(activityTypeName, bookmarkPayload, metadata, cancellationToken);
|
||||
var results = result.WorkflowInstanceResponses.Select(x => new WorkflowExecutionResult(x.WorkflowInstanceId, x.Status, x.SubStatus, x.Bookmarks, x.Incidents, null, null)).ToList();
|
||||
var results = result.WorkflowInstanceResponses.Select(x => new WorkflowExecutionResult(x.WorkflowInstanceId, x.Status, x.SubStatus, x.Bookmarks, x.Incidents, null, new Dictionary<string, object>())).ToList();
|
||||
return new(results);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ public class StimulusProxyWorkflowInbox(
|
|||
new List<Bookmark>(),
|
||||
response.Incidents,
|
||||
null,
|
||||
null)
|
||||
new Dictionary<string, object>())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,14 +3,13 @@ using Elsa.Mediator.Contracts;
|
|||
using Elsa.Workflows.Runtime.Entities;
|
||||
using Elsa.Workflows.Runtime.Notifications;
|
||||
|
||||
namespace Elsa.Workflows.Runtime.Services;
|
||||
namespace Elsa.Workflows.Runtime;
|
||||
|
||||
/// <summary>
|
||||
/// This implementation saves <see cref="ActivityExecutionRecord"/> directly through the store.
|
||||
/// </summary>
|
||||
public class StoreActivityExecutionLogSink(
|
||||
IActivityExecutionStore activityExecutionStore,
|
||||
IActivityExecutionMapper mapper,
|
||||
INotificationSender notificationSender)
|
||||
: ILogRecordSink<ActivityExecutionRecord>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public class ValidatingWorkflowDispatcher(IWorkflowDispatcher decoratedService,
|
|||
private IWorkflowDispatcher DecoratedService { get; set; } = decoratedService;
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<DispatchWorkflowResponse> DispatchAsync(DispatchWorkflowDefinitionRequest request, DispatchWorkflowOptions? options = default, CancellationToken cancellationToken = default)
|
||||
public async Task<DispatchWorkflowResponse> DispatchAsync(DispatchWorkflowDefinitionRequest request, DispatchWorkflowOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!ValidateChannel(options?.Channel))
|
||||
return DispatchWorkflowResponse.UnknownChannel();
|
||||
|
|
@ -24,7 +24,7 @@ public class ValidatingWorkflowDispatcher(IWorkflowDispatcher decoratedService,
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<DispatchWorkflowResponse> DispatchAsync(DispatchWorkflowInstanceRequest request, DispatchWorkflowOptions? options = default, CancellationToken cancellationToken = default)
|
||||
public async Task<DispatchWorkflowResponse> DispatchAsync(DispatchWorkflowInstanceRequest request, DispatchWorkflowOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!ValidateChannel(options?.Channel))
|
||||
return DispatchWorkflowResponse.UnknownChannel();
|
||||
|
|
@ -33,7 +33,7 @@ public class ValidatingWorkflowDispatcher(IWorkflowDispatcher decoratedService,
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<DispatchWorkflowResponse> DispatchAsync(DispatchTriggerWorkflowsRequest request, DispatchWorkflowOptions? options = default, CancellationToken cancellationToken = default)
|
||||
public async Task<DispatchWorkflowResponse> DispatchAsync(DispatchTriggerWorkflowsRequest request, DispatchWorkflowOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!ValidateChannel(options?.Channel))
|
||||
return DispatchWorkflowResponse.UnknownChannel();
|
||||
|
|
@ -42,7 +42,7 @@ public class ValidatingWorkflowDispatcher(IWorkflowDispatcher decoratedService,
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<DispatchWorkflowResponse> DispatchAsync(DispatchResumeWorkflowsRequest request, DispatchWorkflowOptions? options = default, CancellationToken cancellationToken = default)
|
||||
public async Task<DispatchWorkflowResponse> DispatchAsync(DispatchResumeWorkflowsRequest request, DispatchWorkflowOptions? options = null, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!ValidateChannel(options?.Channel))
|
||||
return DispatchWorkflowResponse.UnknownChannel();
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class TriggerSignal : CodeActivity
|
|||
/// <inheritdoc />
|
||||
public TriggerSignal(Input<string> eventName, [CallerFilePath] string? source = null, [CallerLineNumber] int? line = null) : this(source, line) => EventName = eventName;
|
||||
|
||||
public Input<string> EventName { get; set; }
|
||||
public Input<string> EventName { get; set; } = null!;
|
||||
|
||||
protected override void Execute(ActivityExecutionContext context)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ public class BulkDispatchWorkflowsTests : AppComponentTest
|
|||
Assert.Equal(WorkflowSubStatus.Finished, result.WorkflowExecutionContext.SubStatus);
|
||||
}
|
||||
|
||||
private async Task<T> GetWorkflowVariableAsync<T>(TestWorkflowExecutionResult result, string variableName)
|
||||
private async Task<T?> GetWorkflowVariableAsync<T>(TestWorkflowExecutionResult result, string variableName)
|
||||
{
|
||||
var variableManager = Scope.ServiceProvider.GetRequiredService<IWorkflowInstanceVariableManager>();
|
||||
var variables = await variableManager.GetVariablesAsync(result.WorkflowExecutionContext);
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ public class FlowchartNextActivityTests
|
|||
var result = await _workflowRunner.RunAsync(workflow);
|
||||
var lines = _capturingTextWriter.Lines.ToList();
|
||||
Assert.Equal(WorkflowSubStatus.Faulted, result.WorkflowState.SubStatus);
|
||||
Assert.Equal(1, result.WorkflowState.Incidents.Count());
|
||||
Assert.Single(result.WorkflowState.Incidents);
|
||||
Assert.Equal("Invalid backward connection: Every path from the source ('WriteLineE') must go through the target ('WriteLineC') when tracing back to the start.", result.WorkflowState.Incidents.First().Message);
|
||||
Assert.Equal(new[]
|
||||
{
|
||||
|
|
|
|||
|
|
@ -30,6 +30,6 @@ public class IncidentStrategyTests
|
|||
var lines = _capturingTextWriter.Lines.ToList();
|
||||
Assert.Equal(expectedOutput, lines);
|
||||
Assert.Equal(expectedSubStatus, workflowState.SubStatus);
|
||||
Assert.Equal(1, workflowState.Incidents.Count);
|
||||
Assert.Single(workflowState.Incidents);
|
||||
}
|
||||
}
|
||||
|
|
@ -24,8 +24,8 @@ public class Tests
|
|||
public async Task Test1()
|
||||
{
|
||||
await _services.PopulateRegistriesAsync();
|
||||
var workflowDefinition = _publisher.New();
|
||||
var root = _serializer.Deserialize(workflowDefinition.StringData);
|
||||
var workflowDefinition = await _publisher.NewAsync();
|
||||
var root = _serializer.Deserialize(workflowDefinition.StringData!);
|
||||
Assert.NotNull(root);
|
||||
}
|
||||
}
|
||||
|
|
@ -79,8 +79,8 @@ public class Tests
|
|||
new(start, writeLine),
|
||||
new(writeLine, end),
|
||||
},
|
||||
RunAsynchronously = false
|
||||
};
|
||||
container.RunAsynchronously = false;
|
||||
|
||||
// Act
|
||||
|
||||
|
|
@ -93,12 +93,11 @@ public class Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async void SerializeSequenceContainerTest()
|
||||
public async Task SerializeSequenceContainerTest()
|
||||
{
|
||||
await _services.PopulateRegistriesAsync();
|
||||
|
||||
// Arrange
|
||||
|
||||
var container = new Sequence
|
||||
{
|
||||
Id = "sequence",
|
||||
|
|
@ -127,9 +126,9 @@ public class Tests
|
|||
{ "int", 10 },
|
||||
{ "bool", false },
|
||||
{ "string", "str"},
|
||||
}
|
||||
},
|
||||
RunAsynchronously = false
|
||||
};
|
||||
container.RunAsynchronously = false;
|
||||
|
||||
// Act
|
||||
|
||||
|
|
@ -142,12 +141,11 @@ public class Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public async void SerializeParallelContainerTest()
|
||||
public async Task SerializeParallelContainerTest()
|
||||
{
|
||||
await _services.PopulateRegistriesAsync();
|
||||
|
||||
// Arrange
|
||||
|
||||
var container = new Workflows.Activities.Parallel
|
||||
{
|
||||
Id = "parallel",
|
||||
|
|
@ -177,9 +175,9 @@ public class Tests
|
|||
{ "int", 10 },
|
||||
{ "bool", false },
|
||||
{ "string", "str"},
|
||||
}
|
||||
},
|
||||
RunAsynchronously = false
|
||||
};
|
||||
container.RunAsynchronously = false;
|
||||
|
||||
// Act
|
||||
|
||||
|
|
@ -199,10 +197,16 @@ public class Tests
|
|||
// Assert.Equivalent has trouble with the Behavior.Owner reference - since these aren't serialzied anyway, ignore them
|
||||
deserializedContainer.Behaviors.Clear();
|
||||
container.Behaviors.Clear();
|
||||
foreach (Activity activity in deserializedContainer.Activities)
|
||||
foreach (var activity1 in deserializedContainer.Activities)
|
||||
{
|
||||
var activity = (Activity)activity1;
|
||||
activity.Behaviors.Clear();
|
||||
foreach (Activity activity in container.Activities)
|
||||
}
|
||||
|
||||
foreach (var activity in container.Activities.Cast<Activity>())
|
||||
{
|
||||
activity.Behaviors.Clear();
|
||||
}
|
||||
|
||||
// strict:false here allows "actual" to have extra public members that aren't part of "expected", and collection
|
||||
// comparison allows "actual" to have more data in it than is present in "expected".
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ public class SerializationTests(ITestOutputHelper testOutputHelper)
|
|||
"StatusCode", "Created"
|
||||
},
|
||||
{
|
||||
"Content", isArray ? (type == typeof(JArray) ? JArray.Parse(jsonContent) : JsonArray.Parse(jsonContent)) : (type == typeof(JObject) ? JObject.Parse(jsonContent) : JsonObject.Parse(jsonContent))
|
||||
"Content", (isArray ? type == typeof(JArray) ? JArray.Parse(jsonContent) : JsonNode.Parse(jsonContent) : type == typeof(JObject) ? JObject.Parse(jsonContent) : JsonNode.Parse(jsonContent))!
|
||||
}
|
||||
};
|
||||
return dict;
|
||||
|
|
|
|||
|
|
@ -45,11 +45,11 @@ public class Tests
|
|||
var description = await activityDescriber.DescribeActivityAsync(typeof(TestActivity));
|
||||
|
||||
var inputDescription = description.Inputs.First();
|
||||
Assert.True(inputDescription.UISpecifications.ContainsKey(InputUIHints.DropDown));
|
||||
Assert.True(inputDescription.UISpecifications!.ContainsKey(InputUIHints.DropDown));
|
||||
Assert.True(inputDescription.UISpecifications[InputUIHints.DropDown] is DropDownProps);
|
||||
var dropDownProperties = (DropDownProps) inputDescription.UISpecifications[InputUIHints.DropDown];
|
||||
|
||||
Assert.Collection(dropDownProperties.SelectList.Items,
|
||||
Assert.Collection(dropDownProperties.SelectList!.Items,
|
||||
item => { Assert.Equal("OptionsAreNice", item.Text); Assert.Equal("OptionsAreNice", item.Value); },
|
||||
item => { Assert.Equal("ToHave", item.Text); Assert.Equal("ToHave", item.Value); },
|
||||
item => { Assert.Equal("IfYouCanChooseThem", item.Text); Assert.Equal("IfYouCanChooseThem", item.Value); });
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ namespace Elsa.Workflows.PerformanceTests;
|
|||
[Config(typeof(Config))]
|
||||
public class ConsoleActivitiesBenchmark
|
||||
{
|
||||
private WriteLine _writeLineWorkflow;
|
||||
private IWorkflowRunner _workflowRunner;
|
||||
private ServiceProvider _serviceProvider;
|
||||
private WriteLine _writeLineWorkflow = null!;
|
||||
private IWorkflowRunner _workflowRunner = null!;
|
||||
private ServiceProvider _serviceProvider = null!;
|
||||
|
||||
[GlobalSetup]
|
||||
public void GlobalSetup()
|
||||
|
|
@ -21,7 +21,7 @@ public class ConsoleActivitiesBenchmark
|
|||
_serviceProvider = services.BuildServiceProvider();
|
||||
_workflowRunner = _serviceProvider.GetRequiredService<IWorkflowRunner>();
|
||||
|
||||
_writeLineWorkflow = new WriteLine("Hello, World!");
|
||||
_writeLineWorkflow = new("Hello, World!");
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public class ExecuteWorkflowTests
|
|||
opts.CorrelationId == DefaultCorrelationId &&
|
||||
opts.Input != null && opts.Input.ContainsKey("Key1") && (string)opts.Input["Key1"] == "Value1" &&
|
||||
opts.Input.ContainsKey("ParentInstanceId") && (string)opts.Input["ParentInstanceId"] == parentInstanceId &&
|
||||
opts.Properties.ContainsKey("ParentInstanceId") && (string)opts.Properties["ParentInstanceId"] == parentInstanceId &&
|
||||
opts.Properties!.ContainsKey("ParentInstanceId") && (string)opts.Properties["ParentInstanceId"] == parentInstanceId &&
|
||||
(waitForCompletion ? opts.Properties.ContainsKey("WaitForCompletion") && (bool)opts.Properties["WaitForCompletion"] : !opts.Properties.ContainsKey("WaitForCompletion"))
|
||||
),
|
||||
Arg.Any<CancellationToken>()
|
||||
|
|
@ -226,7 +226,7 @@ public class ExecuteWorkflowTests
|
|||
{
|
||||
Status = status,
|
||||
SubStatus = subStatus,
|
||||
Output = output
|
||||
Output = output ?? new Dictionary<string, object>()
|
||||
};
|
||||
var workflowResult = new RunWorkflowResult(null!, workflowState, workflow, null, Journal.Empty);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue