From 490c8a2c9e4bc3884869960194a80a9a1efc2406 Mon Sep 17 00:00:00 2001 From: Sipke Schoorstra Date: Wed, 12 Nov 2025 15:53:23 +0100 Subject: [PATCH] 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> --- Directory.Build.props | 4 +- .../Resilience/Models/RetryAttempt.cs | 2 +- .../Models/StorageDriverDescriptor.cs | 2 + .../Extensions/HandlerExtensions.cs | 3 +- .../CommandHandlerInvokerMiddleware.cs | 2 + .../Elsa.Mediator/Services/DefaultMediator.cs | 1 + .../Models/NewAlterationJob.cs | 4 +- .../Endpoints/Alterations/Submit/Response.cs | 2 +- .../Options/DistributedLockingOptions.cs | 2 +- .../Extensions/TypeAliasRegistryExtensions.cs | 3 +- .../Elsa.Http/Contexts/DownloadableContext.cs | 6 +- .../UIHints/HttpContentTypeOptionsProvider.cs | 2 +- .../Extensions/ModuleExtensions.cs | 6 +- .../DbSchemaAwareMigrationAssembly.cs | 4 +- .../Elsa.Persistence.EFCore.Common.csproj | 1 + .../ResilientActivityDescriptorModifier.cs | 2 +- .../ActivityDescriptors/Get/Models.cs | 2 +- .../Variables/Post/Endpoint.cs | 2 +- .../Models/ActivityPathSegment.cs | 1 + .../Serialization/ArgumentJsonConverter.cs | 2 + .../Activities/Flowchart.Counters.cs | 1 - .../Activities/ForEachT.cs | 3 +- .../Contracts/IWorkflowStateSerializer.cs | 1 - .../MemoryBlockReferenceExtensions.cs | 4 +- .../Elsa.Workflows.Core/Models/Bookmark.cs | 1 + .../UIHints/CheckList/CheckList.cs | 2 +- .../UIHints/RadioList/RadioList.cs | 2 +- .../Models/WorkflowDefinitionModel.cs | 4 +- .../WorkflowDefinitionPublished.cs | 1 + .../WorkflowDefinitionValidating.cs | 1 + .../Activities/DispatchWorkflow.cs | 2 +- .../IWorkflowDefinitionStorePopulator.cs | 2 +- .../Features/WorkflowRuntimeFeature.cs | 4 +- .../Notifications/IndexedWorkflowBookmarks.cs | 8 +- .../Notifications/RunTaskRequest.cs | 2 +- .../Notifications/WorkflowBookmarksIndexed.cs | 1 - .../WorkflowBookmarksPersisted.cs | 1 - .../Requests/UpdateBookmarksRequest.cs | 2 +- .../Services/ObsoleteWorkflowRuntime.cs | 1 + .../Services/ValidatingWorkflowDispatcher.cs | 1 + .../Http/WriteFileHttpResponseTests.cs | 82 ++++++++++--------- 41 files changed, 98 insertions(+), 81 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 171bc74c7..969fcc3f5 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -33,7 +33,9 @@ $(NoWarn);CS0162;CS1591 + + $(NoWarn);CS0618 - $(NoWarn);IL2026;IL2046;IL2057;IL2067;IL2070;IL2072;IL2075;IL2087;IL2091 + $(NoWarn);IL2026;IL2046;IL2057;IL2067;IL2070;IL2072;IL2075;IL2087;IL2091;IL2111 \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Resources/Resilience/Models/RetryAttempt.cs b/src/clients/Elsa.Api.Client/Resources/Resilience/Models/RetryAttempt.cs index f76518386..4cfcf48a1 100644 --- a/src/clients/Elsa.Api.Client/Resources/Resilience/Models/RetryAttempt.cs +++ b/src/clients/Elsa.Api.Client/Resources/Resilience/Models/RetryAttempt.cs @@ -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 Details { get; set; } + public IDictionary Details { get; set; } = null!; } \ No newline at end of file diff --git a/src/clients/Elsa.Api.Client/Resources/StorageDrivers/Models/StorageDriverDescriptor.cs b/src/clients/Elsa.Api.Client/Resources/StorageDrivers/Models/StorageDriverDescriptor.cs index 835893b38..eb1b7241c 100644 --- a/src/clients/Elsa.Api.Client/Resources/StorageDrivers/Models/StorageDriverDescriptor.cs +++ b/src/clients/Elsa.Api.Client/Resources/StorageDrivers/Models/StorageDriverDescriptor.cs @@ -5,4 +5,6 @@ namespace Elsa.Api.Client.Resources.StorageDrivers.Models; /// /// The type name of the storage driver. /// The display name of the storage driver. +/// The priority of the storage driver. +/// Indicates whether the storage driver is deprecated. public record StorageDriverDescriptor(string TypeName, string DisplayName, double Priority = 0, bool Deprecated = false); \ No newline at end of file diff --git a/src/common/Elsa.Mediator/Extensions/HandlerExtensions.cs b/src/common/Elsa.Mediator/Extensions/HandlerExtensions.cs index 5ac381cb0..695268c58 100644 --- a/src/common/Elsa.Mediator/Extensions/HandlerExtensions.cs +++ b/src/common/Elsa.Mediator/Extensions/HandlerExtensions.cs @@ -42,8 +42,7 @@ public static class HandlerExtensions /// /// The handler to invoke. /// The handle method. - /// The notification to handle. - /// The cancellation token. + /// The notification context containing the notification and cancellation token. public static Task InvokeAsync(this INotificationHandler handler, MethodBase handleMethod, NotificationContext notificationContext) { var notification = notificationContext.Notification; diff --git a/src/common/Elsa.Mediator/Middleware/Command/Components/CommandHandlerInvokerMiddleware.cs b/src/common/Elsa.Mediator/Middleware/Command/Components/CommandHandlerInvokerMiddleware.cs index 47cceb0d9..645181b95 100644 --- a/src/common/Elsa.Mediator/Middleware/Command/Components/CommandHandlerInvokerMiddleware.cs +++ b/src/common/Elsa.Mediator/Middleware/Command/Components/CommandHandlerInvokerMiddleware.cs @@ -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 { /// + [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. diff --git a/src/common/Elsa.Mediator/Services/DefaultMediator.cs b/src/common/Elsa.Mediator/Services/DefaultMediator.cs index 40587c3b7..3428e283f 100644 --- a/src/common/Elsa.Mediator/Services/DefaultMediator.cs +++ b/src/common/Elsa.Mediator/Services/DefaultMediator.cs @@ -28,6 +28,7 @@ public class DefaultMediator : IMediator /// The command pipeline. /// The notification pipeline. /// The mediator options. + /// The service provider. public DefaultMediator( IRequestPipeline requestPipeline, ICommandPipeline commandPipeline, diff --git a/src/modules/Elsa.Alterations.Core/Models/NewAlterationJob.cs b/src/modules/Elsa.Alterations.Core/Models/NewAlterationJob.cs index 8b994b647..0338c82d6 100644 --- a/src/modules/Elsa.Alterations.Core/Models/NewAlterationJob.cs +++ b/src/modules/Elsa.Alterations.Core/Models/NewAlterationJob.cs @@ -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!; } \ No newline at end of file diff --git a/src/modules/Elsa.Alterations/Endpoints/Alterations/Submit/Response.cs b/src/modules/Elsa.Alterations/Endpoints/Alterations/Submit/Response.cs index f888d378f..7738820fa 100644 --- a/src/modules/Elsa.Alterations/Endpoints/Alterations/Submit/Response.cs +++ b/src/modules/Elsa.Alterations/Endpoints/Alterations/Submit/Response.cs @@ -1,6 +1,6 @@ namespace Elsa.Alterations.Endpoints.Alterations.Submit; /// -/// The response from the endpoint. +/// The response from the Submit endpoint. /// public record Response(string PlanId); \ No newline at end of file diff --git a/src/modules/Elsa.Common/DistributedHosting/Options/DistributedLockingOptions.cs b/src/modules/Elsa.Common/DistributedHosting/Options/DistributedLockingOptions.cs index bfb1a786a..e37ee6074 100644 --- a/src/modules/Elsa.Common/DistributedHosting/Options/DistributedLockingOptions.cs +++ b/src/modules/Elsa.Common/DistributedHosting/Options/DistributedLockingOptions.cs @@ -3,7 +3,7 @@ using JetBrains.Annotations; namespace Elsa.Common.DistributedHosting; /// -/// Provides options related to distributed locking, which is used by . +/// Provides options related to distributed locking, which is used by the workflow runtime. /// [UsedImplicitly] public class DistributedLockingOptions diff --git a/src/modules/Elsa.Expressions.JavaScript/Extensions/TypeAliasRegistryExtensions.cs b/src/modules/Elsa.Expressions.JavaScript/Extensions/TypeAliasRegistryExtensions.cs index 0d717c0f0..6491ac9a0 100644 --- a/src/modules/Elsa.Expressions.JavaScript/Extensions/TypeAliasRegistryExtensions.cs +++ b/src/modules/Elsa.Expressions.JavaScript/Extensions/TypeAliasRegistryExtensions.cs @@ -9,8 +9,9 @@ namespace Elsa.Expressions.JavaScript.Extensions; public static class TypeAliasRegistryExtensions { /// - /// Register type with the specified alias. + /// Register type with the specified alias. /// + /// The type to register. public static void RegisterType(this ITypeAliasRegistry registry, string alias) => registry.RegisterType(typeof(T), alias); /// diff --git a/src/modules/Elsa.Http/Contexts/DownloadableContext.cs b/src/modules/Elsa.Http/Contexts/DownloadableContext.cs index cfe7b7c89..daa889c2d 100644 --- a/src/modules/Elsa.Http/Contexts/DownloadableContext.cs +++ b/src/modules/Elsa.Http/Contexts/DownloadableContext.cs @@ -7,10 +7,10 @@ namespace Elsa.Http.Contexts; /// /// The manager. /// The content to get downloadables from. -/// An optional ETag. +/// The downloadable options. /// The cancellation token. public record DownloadableContext( - IDownloadableManager Manager, - object Content, + IDownloadableManager Manager, + object Content, DownloadableOptions Options, CancellationToken CancellationToken); \ No newline at end of file diff --git a/src/modules/Elsa.Http/UIHints/HttpContentTypeOptionsProvider.cs b/src/modules/Elsa.Http/UIHints/HttpContentTypeOptionsProvider.cs index fee5eb3ab..24c3f7146 100644 --- a/src/modules/Elsa.Http/UIHints/HttpContentTypeOptionsProvider.cs +++ b/src/modules/Elsa.Http/UIHints/HttpContentTypeOptionsProvider.cs @@ -5,7 +5,7 @@ using Elsa.Workflows.UIHints.Dropdown; namespace Elsa.Http.UIHints; /// -/// Provides options for the activity's property. +/// Provides options for the activity's property. /// public class HttpContentTypeOptionsProvider : DropDownOptionsProviderBase { diff --git a/src/modules/Elsa.Identity/Extensions/ModuleExtensions.cs b/src/modules/Elsa.Identity/Extensions/ModuleExtensions.cs index a0badc6b2..de6762a28 100644 --- a/src/modules/Elsa.Identity/Extensions/ModuleExtensions.cs +++ b/src/modules/Elsa.Identity/Extensions/ModuleExtensions.cs @@ -10,7 +10,7 @@ namespace Elsa.Extensions; public static class ModuleExtensions { /// - /// Installs & configures the feature. + /// Installs and configures the feature. /// public static IModule UseIdentity(this IModule module, Action? configure = null) { @@ -19,7 +19,7 @@ public static class ModuleExtensions } /// - /// Installs & configures the feature. + /// Installs and configures the feature. /// 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 } /// - /// Installs & configures the feature. + /// Installs and configures the feature. /// public static IModule UseDefaultAuthentication(this IModule module, Action? configure = null) { diff --git a/src/modules/Elsa.Persistence.EFCore.Common/DbSchemaAwareMigrationAssembly.cs b/src/modules/Elsa.Persistence.EFCore.Common/DbSchemaAwareMigrationAssembly.cs index 5b9b8127a..bdcccf587 100644 --- a/src/modules/Elsa.Persistence.EFCore.Common/DbSchemaAwareMigrationAssembly.cs +++ b/src/modules/Elsa.Persistence.EFCore.Common/DbSchemaAwareMigrationAssembly.cs @@ -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; /// /// Class That enable Schema change for Migration /// +[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, diff --git a/src/modules/Elsa.Persistence.EFCore.Common/Elsa.Persistence.EFCore.Common.csproj b/src/modules/Elsa.Persistence.EFCore.Common/Elsa.Persistence.EFCore.Common.csproj index f6c2ff912..4306e5c1f 100644 --- a/src/modules/Elsa.Persistence.EFCore.Common/Elsa.Persistence.EFCore.Common.csproj +++ b/src/modules/Elsa.Persistence.EFCore.Common/Elsa.Persistence.EFCore.Common.csproj @@ -5,6 +5,7 @@ Provides common Entity Framework Core types for implementing EF Core persistence of varipus ELsa modules. elsa extension module persistence efcore + Elsa.Persistence.EFCore diff --git a/src/modules/Elsa.Resilience/Modifiers/ResilientActivityDescriptorModifier.cs b/src/modules/Elsa.Resilience/Modifiers/ResilientActivityDescriptorModifier.cs index b2a279fe5..0311b1a88 100644 --- a/src/modules/Elsa.Resilience/Modifiers/ResilientActivityDescriptorModifier.cs +++ b/src/modules/Elsa.Resilience/Modifiers/ResilientActivityDescriptorModifier.cs @@ -4,7 +4,7 @@ using Elsa.Workflows.Models; namespace Elsa.Resilience.Modifiers; /// -/// Modifies the of the activity. +/// Modifies the for resilient activities. /// public class ResilientActivityDescriptorModifier : IActivityDescriptorModifier { diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/Get/Models.cs b/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/Get/Models.cs index bad95b669..94e4e61d9 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/Get/Models.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/ActivityDescriptors/Get/Models.cs @@ -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; } } \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Variables/Post/Endpoint.cs b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Variables/Post/Endpoint.cs index 71115061f..ee01d5b34 100644 --- a/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Variables/Post/Endpoint.cs +++ b/src/modules/Elsa.Workflows.Api/Endpoints/WorkflowInstances/Variables/Post/Endpoint.cs @@ -36,7 +36,7 @@ internal class List(IWorkflowInstanceVariableManager workflowInstanceVariableMan internal class Request { - public ICollection Variables { get; set; } + public ICollection Variables { get; set; } = null!; } internal record ResolvedVariableModel(string Id, string Name, object? Value); \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Api/Models/ActivityPathSegment.cs b/src/modules/Elsa.Workflows.Api/Models/ActivityPathSegment.cs index 551f7b529..2da6a890e 100644 --- a/src/modules/Elsa.Workflows.Api/Models/ActivityPathSegment.cs +++ b/src/modules/Elsa.Workflows.Api/Models/ActivityPathSegment.cs @@ -7,4 +7,5 @@ namespace Elsa.Workflows.Api.Models; /// The ID of the activity. /// The type of the activity. /// The name of the port. +/// The name of the activity. public record ActivityPathSegment(string ActivityNodeId, string ActivityId, string ActivityType, string PortName, string ActivityName); \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Api/Serialization/ArgumentJsonConverter.cs b/src/modules/Elsa.Workflows.Api/Serialization/ArgumentJsonConverter.cs index 2af9c2334..febe80558 100644 --- a/src/modules/Elsa.Workflows.Api/Serialization/ArgumentJsonConverter.cs +++ b/src/modules/Elsa.Workflows.Api/Serialization/ArgumentJsonConverter.cs @@ -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 } /// + [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)!; diff --git a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.Counters.cs b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.Counters.cs index 03db3b0d1..7e0194259 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.Counters.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/Flowchart/Activities/Flowchart.Counters.cs @@ -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. /// - /// The flowchart containing the activities. /// The graph representation of the flowchart. /// Tracks activity and connection visits. /// The execution context of the flowchart. diff --git a/src/modules/Elsa.Workflows.Core/Activities/ForEachT.cs b/src/modules/Elsa.Workflows.Core/Activities/ForEachT.cs index 9d9d06901..09efb9cc9 100644 --- a/src/modules/Elsa.Workflows.Core/Activities/ForEachT.cs +++ b/src/modules/Elsa.Workflows.Core/Activities/ForEachT.cs @@ -9,8 +9,9 @@ using Elsa.Workflows.Models; namespace Elsa.Workflows.Activities; /// -/// A strongly-typed for-each construct where is the item type. +/// A strongly-typed for-each construct where is the item type. /// +/// The type of items in the collection to iterate over. public class ForEach : Activity { private const string CurrentIndexProperty = "CurrentIndex"; diff --git a/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowStateSerializer.cs b/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowStateSerializer.cs index de652e991..00f0b0382 100644 --- a/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowStateSerializer.cs +++ b/src/modules/Elsa.Workflows.Core/Contracts/IWorkflowStateSerializer.cs @@ -131,7 +131,6 @@ public interface IWorkflowStateSerializer /// Deserializes the specified serialized state. /// /// The serialized state. - /// The cancellation token. /// The deserialized workflow state. [RequiresUnreferencedCode("The type 'T' may be trimmed from the output. The deserialization process may require access to the type.")] T Deserialize(string serializedState); diff --git a/src/modules/Elsa.Workflows.Core/Extensions/MemoryBlockReferenceExtensions.cs b/src/modules/Elsa.Workflows.Core/Extensions/MemoryBlockReferenceExtensions.cs index e90a454bd..d8a53bbe4 100644 --- a/src/modules/Elsa.Workflows.Core/Extensions/MemoryBlockReferenceExtensions.cs +++ b/src/modules/Elsa.Workflows.Core/Extensions/MemoryBlockReferenceExtensions.cs @@ -15,7 +15,7 @@ public static class MemoryBlockReferenceExtensions /// /// The to get the value from. /// The ID of the memory block to get the value for. - /// The value of the memory reference referenced by the specified . + /// The value of the memory reference referenced by the specified block ID. public static object? Get(this ExpressionExecutionContext context, string blockId) { var matchingContext = context.FindContextContainingBlock(blockId) ?? context; @@ -27,7 +27,7 @@ public static class MemoryBlockReferenceExtensions /// /// The to get the value from. /// The ID of the memory block to get the value for. - /// The value of the memory reference referenced by the specified . + /// The value of the memory reference referenced by the specified block ID. public static object? Get(this ActivityExecutionContext context, string blockId) => context.ExpressionExecutionContext.Get(blockId); /// diff --git a/src/modules/Elsa.Workflows.Core/Models/Bookmark.cs b/src/modules/Elsa.Workflows.Core/Models/Bookmark.cs index e2ba868f8..4b5e7520d 100644 --- a/src/modules/Elsa.Workflows.Core/Models/Bookmark.cs +++ b/src/modules/Elsa.Workflows.Core/Models/Bookmark.cs @@ -15,6 +15,7 @@ namespace Elsa.Workflows.Models; /// The date and time the bookmark was created. /// Whether or not the bookmark should be automatically burned. /// The name of the method on the activity class to invoke when the bookmark is resumed. +/// Whether or not the activity should be automatically completed when the bookmark is resumed. /// Custom properties associated with the bookmark. public record Bookmark( string Id, diff --git a/src/modules/Elsa.Workflows.Core/UIHints/CheckList/CheckList.cs b/src/modules/Elsa.Workflows.Core/UIHints/CheckList/CheckList.cs index 4380ecae1..878a98474 100644 --- a/src/modules/Elsa.Workflows.Core/UIHints/CheckList/CheckList.cs +++ b/src/modules/Elsa.Workflows.Core/UIHints/CheckList/CheckList.cs @@ -8,7 +8,7 @@ public class CheckList /// /// The radio list. /// - public IEnumerable Items { get; set; } + public IEnumerable Items { get; set; } = null!; /// /// The name of the provider that will provide the select list. diff --git a/src/modules/Elsa.Workflows.Core/UIHints/RadioList/RadioList.cs b/src/modules/Elsa.Workflows.Core/UIHints/RadioList/RadioList.cs index ace833be9..a0274cfb6 100644 --- a/src/modules/Elsa.Workflows.Core/UIHints/RadioList/RadioList.cs +++ b/src/modules/Elsa.Workflows.Core/UIHints/RadioList/RadioList.cs @@ -8,7 +8,7 @@ public class RadioList /// /// The radio list. /// - public IEnumerable Items { get; set; } + public IEnumerable Items { get; set; } = null!; /// /// The name of the provider that will provide the select list. diff --git a/src/modules/Elsa.Workflows.Management/Models/WorkflowDefinitionModel.cs b/src/modules/Elsa.Workflows.Management/Models/WorkflowDefinitionModel.cs index 598155655..b9badee90 100644 --- a/src/modules/Elsa.Workflows.Management/Models/WorkflowDefinitionModel.cs +++ b/src/modules/Elsa.Workflows.Management/Models/WorkflowDefinitionModel.cs @@ -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; } diff --git a/src/modules/Elsa.Workflows.Management/Notifications/WorkflowDefinitionPublished.cs b/src/modules/Elsa.Workflows.Management/Notifications/WorkflowDefinitionPublished.cs index 62c84c96c..eed280722 100644 --- a/src/modules/Elsa.Workflows.Management/Notifications/WorkflowDefinitionPublished.cs +++ b/src/modules/Elsa.Workflows.Management/Notifications/WorkflowDefinitionPublished.cs @@ -9,5 +9,6 @@ namespace Elsa.Workflows.Management.Notifications; /// A notification that is sent when a workflow definition is published. /// /// The workflow definition. +/// The affected workflows. [PublicAPI] public record WorkflowDefinitionPublished(WorkflowDefinition WorkflowDefinition, AffectedWorkflows AffectedWorkflows) : INotification; \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Management/Notifications/WorkflowDefinitionValidating.cs b/src/modules/Elsa.Workflows.Management/Notifications/WorkflowDefinitionValidating.cs index 967c56686..2da147834 100644 --- a/src/modules/Elsa.Workflows.Management/Notifications/WorkflowDefinitionValidating.cs +++ b/src/modules/Elsa.Workflows.Management/Notifications/WorkflowDefinitionValidating.cs @@ -8,4 +8,5 @@ namespace Elsa.Workflows.Management.Notifications; /// A request to validate a workflow definition. /// /// The workflow materialized from the definition. +/// The collection of validation errors. public record WorkflowDefinitionValidating(Workflow Workflow, ICollection ValidationErrors) : INotification; \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Activities/DispatchWorkflow.cs b/src/modules/Elsa.Workflows.Runtime/Activities/DispatchWorkflow.cs index 9619e1d73..22046821f 100644 --- a/src/modules/Elsa.Workflows.Runtime/Activities/DispatchWorkflow.cs +++ b/src/modules/Elsa.Workflows.Runtime/Activities/DispatchWorkflow.cs @@ -59,7 +59,7 @@ public class DispatchWorkflow : Activity /// Indicates whether a new trace context should be started for the workflow execution. /// [Input(Description = "Start a new trace context when using Open Telemetry.", Category = "Open Telemetry")] - public Input StartNewTrace { get; set; } + public Input StartNewTrace { get; set; } = null!; /// /// The channel to dispatch the workflow to. diff --git a/src/modules/Elsa.Workflows.Runtime/Contracts/IWorkflowDefinitionStorePopulator.cs b/src/modules/Elsa.Workflows.Runtime/Contracts/IWorkflowDefinitionStorePopulator.cs index 1eabb75bd..389ec0630 100644 --- a/src/modules/Elsa.Workflows.Runtime/Contracts/IWorkflowDefinitionStorePopulator.cs +++ b/src/modules/Elsa.Workflows.Runtime/Contracts/IWorkflowDefinitionStorePopulator.cs @@ -15,7 +15,7 @@ public interface IWorkflowDefinitionStorePopulator Task> PopulateStoreAsync(CancellationToken cancellationToken = default); /// - /// Populates the with workflow definitions provided from implementations. + /// Populates the with workflow definitions provided from implementations. /// /// Whether to index triggers. /// The cancellation token. diff --git a/src/modules/Elsa.Workflows.Runtime/Features/WorkflowRuntimeFeature.cs b/src/modules/Elsa.Workflows.Runtime/Features/WorkflowRuntimeFeature.cs index d7402bbfe..e5ab1d60f 100644 --- a/src/modules/Elsa.Workflows.Runtime/Features/WorkflowRuntimeFeature.cs +++ b/src/modules/Elsa.Workflows.Runtime/Features/WorkflowRuntimeFeature.cs @@ -105,12 +105,12 @@ public class WorkflowRuntimeFeature(IModule module) : FeatureBase(module) public Func BackgroundActivityScheduler { get; set; } = sp => ActivatorUtilities.CreateInstance(sp); /// - /// A factory that instantiates an for an . + /// A factory that instantiates a log record sink for an . /// public Func> ActivityExecutionLogSink { get; set; } = sp => sp.GetRequiredService(); /// - /// A factory that instantiates an for an . + /// A factory that instantiates a log record sink for an . /// public Func> WorkflowExecutionLogSink { get; set; } = sp => sp.GetRequiredService(); diff --git a/src/modules/Elsa.Workflows.Runtime/Notifications/IndexedWorkflowBookmarks.cs b/src/modules/Elsa.Workflows.Runtime/Notifications/IndexedWorkflowBookmarks.cs index 500564992..f8861ab3c 100644 --- a/src/modules/Elsa.Workflows.Runtime/Notifications/IndexedWorkflowBookmarks.cs +++ b/src/modules/Elsa.Workflows.Runtime/Notifications/IndexedWorkflowBookmarks.cs @@ -3,14 +3,14 @@ using Elsa.Workflows.Models; namespace Elsa.Workflows.Runtime.Notifications; /// -/// Contains the bookmarks that were added, removed, or unchanged. +/// Contains the bookmarks that were added, removed, or unchanged. /// -/// The workflow instance ID. +/// The workflow execution context. /// The bookmarks that were added. /// The bookmarks that were removed. /// The bookmarks that were unchanged. public record IndexedWorkflowBookmarks( WorkflowExecutionContext WorkflowExecutionContext, - ICollection AddedBookmarks, - ICollection RemovedBookmarks, + ICollection AddedBookmarks, + ICollection RemovedBookmarks, ICollection UnchangedBookmarks); \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Notifications/RunTaskRequest.cs b/src/modules/Elsa.Workflows.Runtime/Notifications/RunTaskRequest.cs index 2aaddb867..10e73c572 100644 --- a/src/modules/Elsa.Workflows.Runtime/Notifications/RunTaskRequest.cs +++ b/src/modules/Elsa.Workflows.Runtime/Notifications/RunTaskRequest.cs @@ -5,7 +5,7 @@ namespace Elsa.Workflows.Runtime.Notifications; /// /// A domain event that applications can subscribe to in order to handle tasks requested by a workflow. /// -/// name="ActivityExecutionContext">The context of the activity that requested the task to run. +/// The context of the activity that requested the task to run. /// A unique identifier for an individual task request. /// The name of the task requested to run. /// Any additional parameters to send to the task. diff --git a/src/modules/Elsa.Workflows.Runtime/Notifications/WorkflowBookmarksIndexed.cs b/src/modules/Elsa.Workflows.Runtime/Notifications/WorkflowBookmarksIndexed.cs index 6303effd1..fe1ddd4dc 100644 --- a/src/modules/Elsa.Workflows.Runtime/Notifications/WorkflowBookmarksIndexed.cs +++ b/src/modules/Elsa.Workflows.Runtime/Notifications/WorkflowBookmarksIndexed.cs @@ -5,7 +5,6 @@ namespace Elsa.Workflows.Runtime.Notifications; /// /// A notification that is sent when the bookmarks of a workflow instance have been indexed. /// -/// The workflow execution context. /// The bookmarks that were added, removed, or unchanged. public record WorkflowBookmarksIndexed(IndexedWorkflowBookmarks IndexedWorkflowBookmarks) : INotification; diff --git a/src/modules/Elsa.Workflows.Runtime/Notifications/WorkflowBookmarksPersisted.cs b/src/modules/Elsa.Workflows.Runtime/Notifications/WorkflowBookmarksPersisted.cs index b5b5f2fb2..2d176c39b 100644 --- a/src/modules/Elsa.Workflows.Runtime/Notifications/WorkflowBookmarksPersisted.cs +++ b/src/modules/Elsa.Workflows.Runtime/Notifications/WorkflowBookmarksPersisted.cs @@ -7,6 +7,5 @@ namespace Elsa.Workflows.Runtime.Notifications; /// /// Published when the bookmarks of a workflow instance have been persisted. /// -/// The workflow execution context. /// The bookmarks that were added, removed, or unchanged. public record WorkflowBookmarksPersisted(Diff Diff) : INotification; \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Requests/UpdateBookmarksRequest.cs b/src/modules/Elsa.Workflows.Runtime/Requests/UpdateBookmarksRequest.cs index b6e6b145d..44e7e377b 100644 --- a/src/modules/Elsa.Workflows.Runtime/Requests/UpdateBookmarksRequest.cs +++ b/src/modules/Elsa.Workflows.Runtime/Requests/UpdateBookmarksRequest.cs @@ -6,7 +6,7 @@ namespace Elsa.Workflows.Runtime.Requests; /// /// Published when bookmarks needs to be updated. /// -/// The workflow instance ID. +/// The workflow execution context. /// A diff of the bookmarks. /// The correlation ID, if any. public record UpdateBookmarksRequest(WorkflowExecutionContext WorkflowExecutionContext, Diff Diff, string? CorrelationId = default); \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime/Services/ObsoleteWorkflowRuntime.cs b/src/modules/Elsa.Workflows.Runtime/Services/ObsoleteWorkflowRuntime.cs index 33cafbe82..f836f98a7 100644 --- a/src/modules/Elsa.Workflows.Runtime/Services/ObsoleteWorkflowRuntime.cs +++ b/src/modules/Elsa.Workflows.Runtime/Services/ObsoleteWorkflowRuntime.cs @@ -1,3 +1,4 @@ + using Elsa.Common.Models; using Elsa.Workflows.Management; using Elsa.Workflows.Management.Filters; diff --git a/src/modules/Elsa.Workflows.Runtime/Services/ValidatingWorkflowDispatcher.cs b/src/modules/Elsa.Workflows.Runtime/Services/ValidatingWorkflowDispatcher.cs index 6a9c448a1..1126c3031 100644 --- a/src/modules/Elsa.Workflows.Runtime/Services/ValidatingWorkflowDispatcher.cs +++ b/src/modules/Elsa.Workflows.Runtime/Services/ValidatingWorkflowDispatcher.cs @@ -9,6 +9,7 @@ namespace Elsa.Workflows.Runtime; /// Validates the workflow request before dispatching it to the workflow dispatcher. /// /// The workflow dispatcher to decorate. +/// The workflow dispatcher options. public class ValidatingWorkflowDispatcher(IWorkflowDispatcher decoratedService, IOptions dispatcherOptions) : IWorkflowDispatcher { private IWorkflowDispatcher DecoratedService { get; set; } = decoratedService; diff --git a/test/unit/Elsa.Activities.UnitTests/Http/WriteFileHttpResponseTests.cs b/test/unit/Elsa.Activities.UnitTests/Http/WriteFileHttpResponseTests.cs index 7379ea8d5..12b15ca1d 100644 --- a/test/unit/Elsa.Activities.UnitTests/Http/WriteFileHttpResponseTests.cs +++ b/test/unit/Elsa.Activities.UnitTests/Http/WriteFileHttpResponseTests.cs @@ -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(testContent); - activity.ContentType = new Input(contentType); - activity.Filename = new Input(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(content); - activity.Filename = new Input("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(testBytes); - activity.Filename = new Input("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(stream); - activity.Filename = new Input("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(testUri); - activity.Filename = new Input("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(files); - activity.Filename = new Input("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?)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(Array.Empty()); + activity.Content = new(Array.Empty()); // 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(testContent); - activity.EntityTag = new Input(entityTag); - activity.EnableResumableDownloads = new Input(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(testContent); - activity.EnableResumableDownloads = new Input(true); - activity.EntityTag = new Input("\"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(testContent); - activity.EnableResumableDownloads = new Input(false); - activity.EntityTag = new Input("\"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(testContent); - activity.Filename = new Input(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(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(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(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(testContent); - activity.EntityTag = new Input("W/\"weak-etag\""); // Malformed weak ETag format - activity.EnableResumableDownloads = new Input(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(async () => @@ -548,14 +549,14 @@ public class WriteFileHttpResponseTests } else { - services.AddSingleton(_ => new object()); + services.AddSingleton(_ => 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",