Addresses warnings and enforces null safety (#7050)
* Simplify test setup by removing `Input` wrapper and fix trimming warnings with `UnconditionalSuppressMessage` annotations. * Add trimming warning suppression to `ArgumentJsonConverter` with `UnconditionalSuppressMessage` - Annotated `Read` method to suppress `IL2055` warning caused by dynamic type resolution. - Provided justification reflecting dynamic type registration in the well-known type registry. * Add root namespace to project file and suppress EF Core usage warning - Added `RootNamespace` property to `Elsa.Persistence.EFCore.Common.csproj` for consistency. - Annotated `DbSchemaAwareMigrationAssembly` with `SuppressMessage` to suppress EF1001 usage warning and provide justification. * Suppress obsolete API warnings in workflow runtime projects - Added `#pragma warning disable CS0618` to suppress obsolete member warnings in `ObsoleteWorkflowRuntime.cs`, `LocalWorkflowRuntime.Obsolete.cs`, and `DistributedWorkflowRuntime.Obsolete.cs`. - Updated `Directory.Build.props` to globally suppress `CS0618` for backward compatibility during migration. * Annotate properties with non-nullable default initializers across modules to enforce null safety. * Add `Priority` and `Deprecated` properties to `StorageDriverDescriptor` model * Update src/modules/Elsa.Workflows.Runtime.Distributed/Services/DistributedWorkflowRuntime.Obsolete.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/modules/Elsa.Workflows.Runtime/Services/ObsoleteWorkflowRuntime.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/modules/Elsa.Workflows.Runtime/Services/LocalWorkflowRuntime.Obsolete.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Clean up XML comments and improve consistency across modules. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
8747151330
commit
490c8a2c9e
|
|
@ -33,7 +33,9 @@
|
|||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<NoWarn>$(NoWarn);CS0162;CS1591</NoWarn>
|
||||
<!-- Obsolete API warnings - Suppressed for backward compatibility during migration period -->
|
||||
<NoWarn>$(NoWarn);CS0618</NoWarn>
|
||||
<!-- IL trimming warnings -->
|
||||
<NoWarn>$(NoWarn);IL2026;IL2046;IL2057;IL2067;IL2070;IL2072;IL2075;IL2087;IL2091</NoWarn>
|
||||
<NoWarn>$(NoWarn);IL2026;IL2046;IL2057;IL2067;IL2070;IL2072;IL2075;IL2087;IL2091;IL2111</NoWarn>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
|
@ -9,5 +9,5 @@ public class RetryAttemptRecord : Entity
|
|||
public string WorkflowInstanceId { get; set; } = null!;
|
||||
public int AttemptNumber { get; set; }
|
||||
public TimeSpan RetryDelay { get; set; }
|
||||
public IDictionary<string, string?> Details { get; set; }
|
||||
public IDictionary<string, string?> Details { get; set; } = null!;
|
||||
}
|
||||
|
|
@ -5,4 +5,6 @@ namespace Elsa.Api.Client.Resources.StorageDrivers.Models;
|
|||
/// </summary>
|
||||
/// <param name="TypeName">The type name of the storage driver.</param>
|
||||
/// <param name="DisplayName">The display name of the storage driver.</param>
|
||||
/// <param name="Priority">The priority of the storage driver.</param>
|
||||
/// <param name="Deprecated">Indicates whether the storage driver is deprecated.</param>
|
||||
public record StorageDriverDescriptor(string TypeName, string DisplayName, double Priority = 0, bool Deprecated = false);
|
||||
|
|
@ -42,8 +42,7 @@ public static class HandlerExtensions
|
|||
/// </summary>
|
||||
/// <param name="handler">The handler to invoke.</param>
|
||||
/// <param name="handleMethod">The handle method.</param>
|
||||
/// <param name="notificationContext">The notification to handle.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
/// <param name="notificationContext">The notification context containing the notification and cancellation token.</param>
|
||||
public static Task InvokeAsync(this INotificationHandler handler, MethodBase handleMethod, NotificationContext notificationContext)
|
||||
{
|
||||
var notification = notificationContext.Notification;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using Elsa.Mediator.Contexts;
|
||||
using Elsa.Mediator.Contracts;
|
||||
using Elsa.Mediator.Middleware.Command.Contracts;
|
||||
|
|
@ -13,6 +14,7 @@ namespace Elsa.Mediator.Middleware.Command.Components;
|
|||
public class CommandHandlerInvokerMiddleware(CommandMiddlewareDelegate next) : ICommandMiddleware
|
||||
{
|
||||
/// <inheritdoc />
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2060:Call to MakeGenericMethod can not be statically analyzed", Justification = "The result type is determined at runtime from command types and handlers are registered in DI.")]
|
||||
public async ValueTask InvokeAsync(CommandContext context)
|
||||
{
|
||||
// Find all handlers for the specified command.
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ public class DefaultMediator : IMediator
|
|||
/// <param name="commandPipeline">The command pipeline.</param>
|
||||
/// <param name="notificationPipeline">The notification pipeline.</param>
|
||||
/// <param name="options">The mediator options.</param>
|
||||
/// <param name="serviceProvider">The service provider.</param>
|
||||
public DefaultMediator(
|
||||
IRequestPipeline requestPipeline,
|
||||
ICommandPipeline commandPipeline,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@ namespace Elsa.Alterations.Core.Models;
|
|||
|
||||
public class NewAlterationJob
|
||||
{
|
||||
public string PlanId { get; set; }
|
||||
public string WorkflowInstanceId { get; set; }
|
||||
public string PlanId { get; set; } = null!;
|
||||
public string WorkflowInstanceId { get; set; } = null!;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
namespace Elsa.Alterations.Endpoints.Alterations.Submit;
|
||||
|
||||
/// <summary>
|
||||
/// The response from the <see cref="Execute"/> endpoint.
|
||||
/// The response from the Submit endpoint.
|
||||
/// </summary>
|
||||
public record Response(string PlanId);
|
||||
|
|
@ -3,7 +3,7 @@ using JetBrains.Annotations;
|
|||
namespace Elsa.Common.DistributedHosting;
|
||||
|
||||
/// <summary>
|
||||
/// Provides options related to distributed locking, which is used by <see cref="DefaultWorkflowRuntime"/>.
|
||||
/// Provides options related to distributed locking, which is used by the workflow runtime.
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public class DistributedLockingOptions
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ namespace Elsa.Expressions.JavaScript.Extensions;
|
|||
public static class TypeAliasRegistryExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Register type <see cref="T"/> with the specified alias.
|
||||
/// Register type <typeparamref name="T"/> with the specified alias.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to register.</typeparam>
|
||||
public static void RegisterType<T>(this ITypeAliasRegistry registry, string alias) => registry.RegisterType(typeof(T), alias);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ namespace Elsa.Http.Contexts;
|
|||
/// </summary>
|
||||
/// <param name="Manager">The manager.</param>
|
||||
/// <param name="Content">The content to get downloadables from.</param>
|
||||
/// <param name="ETag">An optional ETag.</param>
|
||||
/// <param name="Options">The downloadable options.</param>
|
||||
/// <param name="CancellationToken">The cancellation token.</param>
|
||||
public record DownloadableContext(
|
||||
IDownloadableManager Manager,
|
||||
object Content,
|
||||
IDownloadableManager Manager,
|
||||
object Content,
|
||||
DownloadableOptions Options,
|
||||
CancellationToken CancellationToken);
|
||||
|
|
@ -5,7 +5,7 @@ using Elsa.Workflows.UIHints.Dropdown;
|
|||
namespace Elsa.Http.UIHints;
|
||||
|
||||
/// <summary>
|
||||
/// Provides options for the <see cref="SendHttpRequest"/> activity's <see cref="SendHttpRequest.ContentType"/> property.
|
||||
/// Provides options for the <see cref="SendHttpRequest"/> activity's <see cref="SendHttpRequestBase.ContentType"/> property.
|
||||
/// </summary>
|
||||
public class HttpContentTypeOptionsProvider : DropDownOptionsProviderBase
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace Elsa.Extensions;
|
|||
public static class ModuleExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Installs & configures the <see cref="IdentityFeature"/> feature.
|
||||
/// Installs and configures the <see cref="IdentityFeature"/> feature.
|
||||
/// </summary>
|
||||
public static IModule UseIdentity(this IModule module, Action<IdentityFeature>? configure = null)
|
||||
{
|
||||
|
|
@ -19,7 +19,7 @@ public static class ModuleExtensions
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Installs & configures the <see cref="IdentityFeature"/> feature.
|
||||
/// Installs and configures the <see cref="IdentityFeature"/> feature.
|
||||
/// </summary>
|
||||
public static IModule UseIdentity(this IModule module, string signingKey, string issuer = "http://elsa.api", string audience = "http://elsa.api", TimeSpan? tokenLifetime = null)
|
||||
{
|
||||
|
|
@ -34,7 +34,7 @@ public static class ModuleExtensions
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Installs & configures the <see cref="IdentityFeature"/> feature.
|
||||
/// Installs and configures the <see cref="DefaultAuthenticationFeature"/> feature.
|
||||
/// </summary>
|
||||
public static IModule UseDefaultAuthentication(this IModule module, Action<DefaultAuthenticationFeature>? configure = null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Reflection;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
|
|
@ -10,6 +11,7 @@ namespace Elsa.Persistence.EFCore;
|
|||
/// <summary>
|
||||
/// Class That enable Schema change for Migration
|
||||
/// </summary>
|
||||
[SuppressMessage("Usage", "EF1001:Internal EF Core API usage.", Justification = "Required to customize migration assembly behavior for schema-aware migrations.")]
|
||||
public class DbSchemaAwareMigrationAssembly(
|
||||
ICurrentDbContext currentContext,
|
||||
IDbContextOptions options,
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
Provides common Entity Framework Core types for implementing EF Core persistence of varipus ELsa modules.
|
||||
</Description>
|
||||
<PackageTags>elsa extension module persistence efcore</PackageTags>
|
||||
<RootNamespace>Elsa.Persistence.EFCore</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using Elsa.Workflows.Models;
|
|||
namespace Elsa.Resilience.Modifiers;
|
||||
|
||||
/// <summary>
|
||||
/// Modifies the <see cref="ActivityDescriptor"/> of the <see cref="Cron"/> activity.
|
||||
/// Modifies the <see cref="ActivityDescriptor"/> for resilient activities.
|
||||
/// </summary>
|
||||
public class ResilientActivityDescriptorModifier : IActivityDescriptorModifier
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@ namespace Elsa.Workflows.Api.Endpoints.ActivityDescriptors.Get;
|
|||
|
||||
internal class Request
|
||||
{
|
||||
public string TypeName { get; set; }
|
||||
public string TypeName { get; set; } = null!;
|
||||
public int? Version { get; set; }
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ internal class List(IWorkflowInstanceVariableManager workflowInstanceVariableMan
|
|||
|
||||
internal class Request
|
||||
{
|
||||
public ICollection<VariableUpdateValue> Variables { get; set; }
|
||||
public ICollection<VariableUpdateValue> Variables { get; set; } = null!;
|
||||
}
|
||||
|
||||
internal record ResolvedVariableModel(string Id, string Name, object? Value);
|
||||
|
|
@ -7,4 +7,5 @@ namespace Elsa.Workflows.Api.Models;
|
|||
/// <param name="ActivityId">The ID of the activity.</param>
|
||||
/// <param name="ActivityType">The type of the activity.</param>
|
||||
/// <param name="PortName">The name of the port.</param>
|
||||
/// <param name="ActivityName">The name of the activity.</param>
|
||||
public record ActivityPathSegment(string ActivityNodeId, string ActivityId, string ActivityType, string PortName, string ActivityName);
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
|
|
@ -45,6 +46,7 @@ public class ArgumentJsonConverter : JsonConverter<ArgumentDefinition>
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2055:Call to MakeGenericType can not be statically analyzed", Justification = "Types are dynamically resolved from workflow definitions and registered in the well-known type registry.")]
|
||||
public override ArgumentDefinition Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var jsonObject = (JsonObject)JsonNode.Parse(ref reader)!;
|
||||
|
|
|
|||
|
|
@ -63,7 +63,6 @@ public partial class Flowchart
|
|||
/// This method determines whether an activity should be scheduled based on visited connections,
|
||||
/// forward traversal rules, and backward connections.
|
||||
/// </summary>
|
||||
/// <param name="flowchart">The flowchart containing the activities.</param>
|
||||
/// <param name="flowGraph">The graph representation of the flowchart.</param>
|
||||
/// <param name="flowScope">Tracks activity and connection visits.</param>
|
||||
/// <param name="flowchartContext">The execution context of the flowchart.</param>
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ using Elsa.Workflows.Models;
|
|||
namespace Elsa.Workflows.Activities;
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed for-each construct where <see cref="T"/> is the item type.
|
||||
/// A strongly-typed for-each construct where <typeparamref name="T"/> is the item type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of items in the collection to iterate over.</typeparam>
|
||||
public class ForEach<T> : Activity
|
||||
{
|
||||
private const string CurrentIndexProperty = "CurrentIndex";
|
||||
|
|
|
|||
|
|
@ -131,7 +131,6 @@ public interface IWorkflowStateSerializer
|
|||
/// 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);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public static class MemoryBlockReferenceExtensions
|
|||
/// </summary>
|
||||
/// <param name="context">The <see cref="ExpressionExecutionContext"/> to get the value from.</param>
|
||||
/// <param name="blockId">The ID of the memory block to get the value for.</param>
|
||||
/// <returns>The value of the memory reference referenced by the specified <see cref="blockId"/>.</returns>
|
||||
/// <returns>The value of the memory reference referenced by the specified block ID.</returns>
|
||||
public static object? Get(this ExpressionExecutionContext context, string blockId)
|
||||
{
|
||||
var matchingContext = context.FindContextContainingBlock(blockId) ?? context;
|
||||
|
|
@ -27,7 +27,7 @@ public static class MemoryBlockReferenceExtensions
|
|||
/// </summary>
|
||||
/// <param name="context">The <see cref="ActivityExecutionContext"/> to get the value from.</param>
|
||||
/// <param name="blockId">The ID of the memory block to get the value for.</param>
|
||||
/// <returns>The value of the memory reference referenced by the specified <see cref="blockId"/>.</returns>
|
||||
/// <returns>The value of the memory reference referenced by the specified block ID.</returns>
|
||||
public static object? Get(this ActivityExecutionContext context, string blockId) => context.ExpressionExecutionContext.Get(blockId);
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ namespace Elsa.Workflows.Models;
|
|||
/// <param name="CreatedAt">The date and time the bookmark was created.</param>
|
||||
/// <param name="AutoBurn">Whether or not the bookmark should be automatically burned.</param>
|
||||
/// <param name="CallbackMethodName">The name of the method on the activity class to invoke when the bookmark is resumed.</param>
|
||||
/// <param name="AutoComplete">Whether or not the activity should be automatically completed when the bookmark is resumed.</param>
|
||||
/// <param name="Metadata">Custom properties associated with the bookmark.</param>
|
||||
public record Bookmark(
|
||||
string Id,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public class CheckList
|
|||
/// <summary>
|
||||
/// The radio list.
|
||||
/// </summary>
|
||||
public IEnumerable<CheckListItem> Items { get; set; }
|
||||
public IEnumerable<CheckListItem> Items { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the provider that will provide the select list.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public class RadioList
|
|||
/// <summary>
|
||||
/// The radio list.
|
||||
/// </summary>
|
||||
public IEnumerable<RadioListItem> Items { get; set; }
|
||||
public IEnumerable<RadioListItem> Items { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the provider that will provide the select list.
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ public class WorkflowDefinitionModel
|
|||
Root = root;
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
public string DefinitionId { get; set; }
|
||||
public string Id { get; set; } = null!;
|
||||
public string DefinitionId { get; set; } = null!;
|
||||
public string? TenantId { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
|
|
|
|||
|
|
@ -9,5 +9,6 @@ namespace Elsa.Workflows.Management.Notifications;
|
|||
/// A notification that is sent when a workflow definition is published.
|
||||
/// </summary>
|
||||
/// <param name="WorkflowDefinition">The workflow definition.</param>
|
||||
/// <param name="AffectedWorkflows">The affected workflows.</param>
|
||||
[PublicAPI]
|
||||
public record WorkflowDefinitionPublished(WorkflowDefinition WorkflowDefinition, AffectedWorkflows AffectedWorkflows) : INotification;
|
||||
|
|
@ -8,4 +8,5 @@ namespace Elsa.Workflows.Management.Notifications;
|
|||
/// A request to validate a workflow definition.
|
||||
/// </summary>
|
||||
/// <param name="Workflow">The workflow materialized from the definition.</param>
|
||||
/// <param name="ValidationErrors">The collection of validation errors.</param>
|
||||
public record WorkflowDefinitionValidating(Workflow Workflow, ICollection<WorkflowValidationError> ValidationErrors) : INotification;
|
||||
|
|
@ -59,7 +59,7 @@ public class DispatchWorkflow : Activity<object>
|
|||
/// Indicates whether a new trace context should be started for the workflow execution.
|
||||
/// </summary>
|
||||
[Input(Description = "Start a new trace context when using Open Telemetry.", Category = "Open Telemetry")]
|
||||
public Input<bool> StartNewTrace { get; set; }
|
||||
public Input<bool> StartNewTrace { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The channel to dispatch the workflow to.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public interface IWorkflowDefinitionStorePopulator
|
|||
Task<IEnumerable<WorkflowDefinition>> PopulateStoreAsync(CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Populates the <see cref="IWorkflowDefinitionStore"/> with workflow definitions provided from <see cref="IWorkflowProvider"/> implementations.
|
||||
/// Populates the <see cref="IWorkflowDefinitionStore"/> with workflow definitions provided from <see cref="IWorkflowsProvider"/> implementations.
|
||||
/// </summary>
|
||||
/// <param name="indexTriggers">Whether to index triggers.</param>
|
||||
/// <param name="cancellationToken">The cancellation token.</param>
|
||||
|
|
|
|||
|
|
@ -105,12 +105,12 @@ public class WorkflowRuntimeFeature(IModule module) : FeatureBase(module)
|
|||
public Func<IServiceProvider, IBackgroundActivityScheduler> BackgroundActivityScheduler { get; set; } = sp => ActivatorUtilities.CreateInstance<LocalBackgroundActivityScheduler>(sp);
|
||||
|
||||
/// <summary>
|
||||
/// A factory that instantiates an <see cref="ILogRecordSink"/> for an <see cref="ActivityExecutionRecord"/>.
|
||||
/// A factory that instantiates a log record sink for an <see cref="ActivityExecutionRecord"/>.
|
||||
/// </summary>
|
||||
public Func<IServiceProvider, ILogRecordSink<ActivityExecutionRecord>> ActivityExecutionLogSink { get; set; } = sp => sp.GetRequiredService<StoreActivityExecutionLogSink>();
|
||||
|
||||
/// <summary>
|
||||
/// A factory that instantiates an <see cref="ILogRecordSink"/> for an <see cref="WorkflowExecutionLogRecord"/>.
|
||||
/// A factory that instantiates a log record sink for an <see cref="WorkflowExecutionLogRecord"/>.
|
||||
/// </summary>
|
||||
public Func<IServiceProvider, ILogRecordSink<WorkflowExecutionLogRecord>> WorkflowExecutionLogSink { get; set; } = sp => sp.GetRequiredService<StoreWorkflowExecutionLogSink>();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ using Elsa.Workflows.Models;
|
|||
namespace Elsa.Workflows.Runtime.Notifications;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the bookmarks that were added, removed, or unchanged.
|
||||
/// Contains the bookmarks that were added, removed, or unchanged.
|
||||
/// </summary>
|
||||
/// <param name="InstanceId">The workflow instance ID.</param>
|
||||
/// <param name="WorkflowExecutionContext">The workflow execution context.</param>
|
||||
/// <param name="AddedBookmarks">The bookmarks that were added.</param>
|
||||
/// <param name="RemovedBookmarks">The bookmarks that were removed.</param>
|
||||
/// <param name="UnchangedBookmarks">The bookmarks that were unchanged.</param>
|
||||
public record IndexedWorkflowBookmarks(
|
||||
WorkflowExecutionContext WorkflowExecutionContext,
|
||||
ICollection<Bookmark> AddedBookmarks,
|
||||
ICollection<Bookmark> RemovedBookmarks,
|
||||
ICollection<Bookmark> AddedBookmarks,
|
||||
ICollection<Bookmark> RemovedBookmarks,
|
||||
ICollection<Bookmark> UnchangedBookmarks);
|
||||
|
|
@ -5,7 +5,7 @@ namespace Elsa.Workflows.Runtime.Notifications;
|
|||
/// <summary>
|
||||
/// A domain event that applications can subscribe to in order to handle tasks requested by a workflow.
|
||||
/// </summary>
|
||||
/// <param>name="ActivityExecutionContext">The context of the activity that requested the task to run.</param>
|
||||
/// <param name="ActivityExecutionContext">The context of the activity that requested the task to run.</param>
|
||||
/// <param name="TaskId">A unique identifier for an individual task request.</param>
|
||||
/// <param name="TaskName">The name of the task requested to run.</param>
|
||||
/// <param name="TaskPayload">Any additional parameters to send to the task.</param>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ namespace Elsa.Workflows.Runtime.Notifications;
|
|||
/// <summary>
|
||||
/// A notification that is sent when the bookmarks of a workflow instance have been indexed.
|
||||
/// </summary>
|
||||
/// <param name="WorkflowExecutionContext">The workflow execution context.</param>
|
||||
/// <param name="IndexedWorkflowBookmarks">The bookmarks that were added, removed, or unchanged.</param>
|
||||
public record WorkflowBookmarksIndexed(IndexedWorkflowBookmarks IndexedWorkflowBookmarks) : INotification;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,5 @@ namespace Elsa.Workflows.Runtime.Notifications;
|
|||
/// <summary>
|
||||
/// Published when the bookmarks of a workflow instance have been persisted.
|
||||
/// </summary>
|
||||
/// <param name="Context">The workflow execution context.</param>
|
||||
/// <param name="Diff">The bookmarks that were added, removed, or unchanged.</param>
|
||||
public record WorkflowBookmarksPersisted(Diff<Bookmark> Diff) : INotification;
|
||||
|
|
@ -6,7 +6,7 @@ namespace Elsa.Workflows.Runtime.Requests;
|
|||
/// <summary>
|
||||
/// Published when bookmarks needs to be updated.
|
||||
/// </summary>
|
||||
/// <param name="WorkflowInstanceId">The workflow instance ID.</param>
|
||||
/// <param name="WorkflowExecutionContext">The workflow execution context.</param>
|
||||
/// <param name="Diff">A diff of the bookmarks.</param>
|
||||
/// <param name="CorrelationId">The correlation ID, if any.</param>
|
||||
public record UpdateBookmarksRequest(WorkflowExecutionContext WorkflowExecutionContext, Diff<Bookmark> Diff, string? CorrelationId = default);
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
using Elsa.Common.Models;
|
||||
using Elsa.Workflows.Management;
|
||||
using Elsa.Workflows.Management.Filters;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ namespace Elsa.Workflows.Runtime;
|
|||
/// Validates the workflow request before dispatching it to the workflow dispatcher.
|
||||
/// </summary>
|
||||
/// <param name="decoratedService">The workflow dispatcher to decorate.</param>
|
||||
/// <param name="dispatcherOptions">The workflow dispatcher options.</param>
|
||||
public class ValidatingWorkflowDispatcher(IWorkflowDispatcher decoratedService, IOptions<WorkflowDispatcherOptions> dispatcherOptions) : IWorkflowDispatcher
|
||||
{
|
||||
private IWorkflowDispatcher DecoratedService { get; set; } = decoratedService;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using System.IO.Compression;
|
||||
using Elsa.Common;
|
||||
|
|
@ -29,9 +30,9 @@ public class WriteFileHttpResponseTests
|
|||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
var testContent = "Hello World"u8.ToArray();
|
||||
|
||||
activity.Content = new Input<object>(testContent);
|
||||
activity.ContentType = new Input<string?>(contentType);
|
||||
activity.Filename = new Input<string?>(filename);
|
||||
activity.Content = new(testContent);
|
||||
activity.ContentType = new(contentType);
|
||||
activity.Filename = new(filename);
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -49,8 +50,8 @@ public class WriteFileHttpResponseTests
|
|||
{
|
||||
// Arrange
|
||||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
activity.Content = new Input<object>(content);
|
||||
activity.Filename = new Input<string?>("test.txt");
|
||||
activity.Content = new(content);
|
||||
activity.Filename = new("test.txt");
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -68,8 +69,8 @@ public class WriteFileHttpResponseTests
|
|||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
var testBytes = "Hello World"u8.ToArray();
|
||||
|
||||
activity.Content = new Input<object>(testBytes);
|
||||
activity.Filename = new Input<string?>("test.bin");
|
||||
activity.Content = new(testBytes);
|
||||
activity.Filename = new("test.bin");
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -88,8 +89,8 @@ public class WriteFileHttpResponseTests
|
|||
var testContent = "Stream content";
|
||||
var stream = new MemoryStream(Encoding.UTF8.GetBytes(testContent));
|
||||
|
||||
activity.Content = new Input<object>(stream);
|
||||
activity.Filename = new Input<string?>("stream.txt");
|
||||
activity.Content = new(stream);
|
||||
activity.Filename = new("stream.txt");
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -107,8 +108,8 @@ public class WriteFileHttpResponseTests
|
|||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
var testUri = new Uri("https://example.com/file.txt");
|
||||
|
||||
activity.Content = new Input<object>(testUri);
|
||||
activity.Filename = new Input<string?>("downloaded.txt");
|
||||
activity.Content = new(testUri);
|
||||
activity.Filename = new("downloaded.txt");
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -129,8 +130,8 @@ public class WriteFileHttpResponseTests
|
|||
"File 2 content"u8.ToArray()
|
||||
};
|
||||
|
||||
activity.Content = new Input<object>(files);
|
||||
activity.Filename = new Input<string?>("archive.zip");
|
||||
activity.Content = new(files);
|
||||
activity.Filename = new("archive.zip");
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -146,7 +147,7 @@ public class WriteFileHttpResponseTests
|
|||
{
|
||||
// Arrange
|
||||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
activity.Content = new Input<object>((object?)null!, string.Empty);
|
||||
activity.Content = new((object?)null!, string.Empty);
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -161,7 +162,7 @@ public class WriteFileHttpResponseTests
|
|||
{
|
||||
// Arrange
|
||||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
activity.Content = new Input<object>(Array.Empty<object>());
|
||||
activity.Content = new(Array.Empty<object>());
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -181,9 +182,9 @@ public class WriteFileHttpResponseTests
|
|||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
var testContent = "Hello World"u8.ToArray();
|
||||
|
||||
activity.Content = new Input<object>(testContent);
|
||||
activity.EntityTag = new Input<string?>(entityTag);
|
||||
activity.EnableResumableDownloads = new Input<bool>(true);
|
||||
activity.Content = new(testContent);
|
||||
activity.EntityTag = new(entityTag);
|
||||
activity.EnableResumableDownloads = new(true);
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -202,9 +203,9 @@ public class WriteFileHttpResponseTests
|
|||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
var testContent = "Hello World"u8.ToArray();
|
||||
|
||||
activity.Content = new Input<object>(testContent);
|
||||
activity.EnableResumableDownloads = new Input<bool>(true);
|
||||
activity.EntityTag = new Input<string?>("\"test-etag\"");
|
||||
activity.Content = new(testContent);
|
||||
activity.EnableResumableDownloads = new(true);
|
||||
activity.EntityTag = new("\"test-etag\"");
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -223,9 +224,9 @@ public class WriteFileHttpResponseTests
|
|||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
var testContent = "Hello World"u8.ToArray();
|
||||
|
||||
activity.Content = new Input<object>(testContent);
|
||||
activity.EnableResumableDownloads = new Input<bool>(false);
|
||||
activity.EntityTag = new Input<string?>("\"test-etag\"");
|
||||
activity.Content = new(testContent);
|
||||
activity.EnableResumableDownloads = new(false);
|
||||
activity.EntityTag = new("\"test-etag\"");
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -247,8 +248,8 @@ public class WriteFileHttpResponseTests
|
|||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
var testContent = "Hello World"u8.ToArray();
|
||||
|
||||
activity.Content = new Input<object>(testContent);
|
||||
activity.Filename = new Input<string?>(filename);
|
||||
activity.Content = new(testContent);
|
||||
activity.Filename = new(filename);
|
||||
// ContentType not set, should be determined from filename
|
||||
|
||||
// Act
|
||||
|
|
@ -266,7 +267,7 @@ public class WriteFileHttpResponseTests
|
|||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
var testContent = "Hello World"u8.ToArray();
|
||||
|
||||
activity.Content = new Input<object>(testContent);
|
||||
activity.Content = new(testContent);
|
||||
// Filename not set, should default to "file.bin"
|
||||
|
||||
// Act
|
||||
|
|
@ -306,7 +307,7 @@ public class WriteFileHttpResponseTests
|
|||
// Arrange
|
||||
var activity = new WriteFileHttpResponse();
|
||||
var testContent = "Hello World"u8.ToArray();
|
||||
activity.Content = new Input<object>(testContent);
|
||||
activity.Content = new(testContent);
|
||||
|
||||
var fixture = new ActivityTestFixture(activity);
|
||||
var httpContext = CreateMockHttpContext();
|
||||
|
|
@ -361,7 +362,7 @@ public class WriteFileHttpResponseTests
|
|||
ETag = "\"metadata-etag\""
|
||||
};
|
||||
|
||||
activity.Content = new Input<object>(downloadable);
|
||||
activity.Content = new(downloadable);
|
||||
|
||||
// Act
|
||||
var context = await ExecuteActivityAsync(activity, httpContext);
|
||||
|
|
@ -379,9 +380,9 @@ public class WriteFileHttpResponseTests
|
|||
var (activity, httpContext) = CreateWriteFileHttpResponseActivity();
|
||||
var testContent = "Hello World"u8.ToArray();
|
||||
|
||||
activity.Content = new Input<object>(testContent);
|
||||
activity.EntityTag = new Input<string?>("W/\"weak-etag\""); // Malformed weak ETag format
|
||||
activity.EnableResumableDownloads = new Input<bool>(true);
|
||||
activity.Content = new(testContent);
|
||||
activity.EntityTag = new("W/\"weak-etag\""); // Malformed weak ETag format
|
||||
activity.EnableResumableDownloads = new(true);
|
||||
|
||||
// Act & Assert
|
||||
var exception = await Assert.ThrowsAsync<FormatException>(async () =>
|
||||
|
|
@ -548,14 +549,14 @@ public class WriteFileHttpResponseTests
|
|||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<object>(_ => new object());
|
||||
services.AddSingleton<object>(_ => new());
|
||||
}
|
||||
}
|
||||
|
||||
private static object CreateZipManagerInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
var zipManagerType = typeof(WriteFileHttpResponse).Assembly.GetType("Elsa.Http.Services.ZipManager");
|
||||
if (zipManagerType == null) return new object();
|
||||
if (zipManagerType == null) return new();
|
||||
|
||||
try
|
||||
{
|
||||
|
|
@ -591,13 +592,14 @@ public class WriteFileHttpResponseTests
|
|||
};
|
||||
}
|
||||
|
||||
[UnconditionalSuppressMessage("Trimming", "IL2060:Call to MakeGenericMethod can not be statically analyzed", Justification = "Test helper method that creates mocks dynamically for any logger type.")]
|
||||
private static object CreateLoggerMock(Type loggerType)
|
||||
{
|
||||
try
|
||||
{
|
||||
var mockLoggerMethod = typeof(Substitute).GetMethods()
|
||||
.FirstOrDefault(m => m is { Name: "For", IsGenericMethodDefinition: true } && m.GetParameters().Length == 0);
|
||||
|
||||
|
||||
if (mockLoggerMethod != null)
|
||||
{
|
||||
var genericMethod = mockLoggerMethod.MakeGenericMethod(loggerType);
|
||||
|
|
@ -634,7 +636,7 @@ public class WriteFileHttpResponseTests
|
|||
{
|
||||
// Simplified mock creation for different content types
|
||||
case byte[] byteArray:
|
||||
yield return new Downloadable
|
||||
yield return new()
|
||||
{
|
||||
Stream = new MemoryStream(byteArray),
|
||||
ContentType = null,
|
||||
|
|
@ -642,7 +644,7 @@ public class WriteFileHttpResponseTests
|
|||
};
|
||||
break;
|
||||
case string text:
|
||||
yield return new Downloadable
|
||||
yield return new()
|
||||
{
|
||||
Stream = new MemoryStream(Encoding.UTF8.GetBytes(text)),
|
||||
ContentType = null,
|
||||
|
|
@ -651,7 +653,7 @@ public class WriteFileHttpResponseTests
|
|||
break;
|
||||
case Stream stream:
|
||||
// For Stream objects, return them as-is
|
||||
yield return new Downloadable
|
||||
yield return new()
|
||||
{
|
||||
Stream = stream,
|
||||
ContentType = null,
|
||||
|
|
@ -662,7 +664,7 @@ public class WriteFileHttpResponseTests
|
|||
{
|
||||
// For Uri objects, simulate downloaded content
|
||||
var mockContent = $"Downloaded content from {uri}";
|
||||
yield return new Downloadable
|
||||
yield return new()
|
||||
{
|
||||
Stream = new MemoryStream(Encoding.UTF8.GetBytes(mockContent)),
|
||||
ContentType = null,
|
||||
|
|
@ -710,7 +712,7 @@ public class WriteFileHttpResponseTests
|
|||
}
|
||||
|
||||
memoryStream.Position = 0;
|
||||
return new Downloadable
|
||||
return new()
|
||||
{
|
||||
Stream = memoryStream,
|
||||
ContentType = "application/zip",
|
||||
|
|
|
|||
Loading…
Reference in a new issue