diff --git a/Directory.Packages.props b/Directory.Packages.props index 799be4846..4d2ec3adf 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,7 +4,7 @@ false - 3.6.0-preview.1165 + 3.6.0-preview.1170 9.0.7 9.7.0 @@ -179,7 +179,7 @@ true - 3.5.0-preview.1092 + 3.6.0-preview.1170 9.0.7 diff --git a/Elsa.sln b/Elsa.sln index c75f22b9f..d23fb3914 100644 --- a/Elsa.sln +++ b/Elsa.sln @@ -237,14 +237,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Caching", "src\modules EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "http", "http", "{C55015F0-E9DF-4BF9-8131-D7539E938220}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "io", "io", "{7FD1FD1E-5778-4065-AAA5-1F878129EF77}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.IO", "src\modules\Elsa.IO\Elsa.IO.csproj", "{EB24F9FE-D7BD-4FCC-907E-AE400288C2A5}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.IO.Compression", "src\modules\Elsa.IO.Compression\Elsa.IO.Compression.csproj", "{9CA02818-F7EB-4A0B-B27B-BC74ACD499C9}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.IO.Http", "src\modules\Elsa.IO.Http\Elsa.IO.Http.csproj", "{C583AF05-D517-4B7F-8955-6B61500ED3D8}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Http", "src\modules\Elsa.Http\Elsa.Http.csproj", "{E0B22AB7-7CB5-6D17-562C-4A989DC61F8A}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Expressions.CSharp", "src\modules\Elsa.Expressions.CSharp\Elsa.Expressions.CSharp.csproj", "{16C3FBDE-A832-E3CD-5FBF-F51744D1F79B}" @@ -467,18 +459,6 @@ Global {E7137FB0-1988-4562-AD8D-D0D9D2EE85F6}.Debug|Any CPU.Build.0 = Debug|Any CPU {E7137FB0-1988-4562-AD8D-D0D9D2EE85F6}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7137FB0-1988-4562-AD8D-D0D9D2EE85F6}.Release|Any CPU.Build.0 = Release|Any CPU - {EB24F9FE-D7BD-4FCC-907E-AE400288C2A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EB24F9FE-D7BD-4FCC-907E-AE400288C2A5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EB24F9FE-D7BD-4FCC-907E-AE400288C2A5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EB24F9FE-D7BD-4FCC-907E-AE400288C2A5}.Release|Any CPU.Build.0 = Release|Any CPU - {9CA02818-F7EB-4A0B-B27B-BC74ACD499C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9CA02818-F7EB-4A0B-B27B-BC74ACD499C9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9CA02818-F7EB-4A0B-B27B-BC74ACD499C9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9CA02818-F7EB-4A0B-B27B-BC74ACD499C9}.Release|Any CPU.Build.0 = Release|Any CPU - {C583AF05-D517-4B7F-8955-6B61500ED3D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C583AF05-D517-4B7F-8955-6B61500ED3D8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C583AF05-D517-4B7F-8955-6B61500ED3D8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C583AF05-D517-4B7F-8955-6B61500ED3D8}.Release|Any CPU.Build.0 = Release|Any CPU {6F14B066-DF7B-2409-59D8-CCCA90A4974C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6F14B066-DF7B-2409-59D8-CCCA90A4974C}.Debug|Any CPU.Build.0 = Debug|Any CPU {6F14B066-DF7B-2409-59D8-CCCA90A4974C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -596,10 +576,6 @@ Global {66E2E2CF-967F-4564-89E8-F46FA973C99B} = {986E5482-0482-448C-B9E4-EC67A9474B85} {0A04B1FD-06C0-4271-A910-A08C263DBC44} = {0354F050-3992-4DD4-B0EE-5FBA04AC72B6} {9B80A705-2E31-4012-964A-83963DCDB384} = {0354F050-3992-4DD4-B0EE-5FBA04AC72B6} - {7FD1FD1E-5778-4065-AAA5-1F878129EF77} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79} - {EB24F9FE-D7BD-4FCC-907E-AE400288C2A5} = {7FD1FD1E-5778-4065-AAA5-1F878129EF77} - {9CA02818-F7EB-4A0B-B27B-BC74ACD499C9} = {7FD1FD1E-5778-4065-AAA5-1F878129EF77} - {C583AF05-D517-4B7F-8955-6B61500ED3D8} = {7FD1FD1E-5778-4065-AAA5-1F878129EF77} {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79} {6F14B066-DF7B-2409-59D8-CCCA90A4974C} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} {C55015F0-E9DF-4BF9-8131-D7539E938220} = {5BA4A8FA-F7F4-45B3-AEC8-8886D35AAC79} diff --git a/src/modules/Elsa.IO.Compression/Activities/CreateZipArchive.cs b/src/modules/Elsa.IO.Compression/Activities/CreateZipArchive.cs deleted file mode 100644 index e322d7594..000000000 --- a/src/modules/Elsa.IO.Compression/Activities/CreateZipArchive.cs +++ /dev/null @@ -1,208 +0,0 @@ -using System.IO.Compression; -using System.Text.Json.Serialization; -using Elsa.Extensions; -using Elsa.IO.Contracts; -using Elsa.IO.Extensions; -using Elsa.Workflows; -using Elsa.Workflows.Attributes; -using Elsa.Workflows.Models; -using Elsa.Workflows.UIHints; -using Microsoft.Extensions.Logging; - -namespace Elsa.IO.Compression.Activities; - -/// -/// Creates a ZIP archive from a collection of entries. -/// -[Activity("Elsa", "Compression", "Creates a ZIP archive from a collection of entries.", DisplayName = "Create Zip Archive")] -public class CreateZipArchive : CodeActivity -{ - private const string DefaultArchiveName = "archive.zip"; - private const string ZipExtension = ".zip"; - private const string DefaultEntryNameFormat = "entry_{0}"; - - /// - [JsonConstructor] - public CreateZipArchive(string? source = null, int? line = null) : base(source, line) - { - } - - /// - /// The entries to include in the ZIP archive. Can be byte[], Stream, file path, file URL, base64 string, ZipEntry objects, or arrays of these types. - /// - [Input( - Description = "The entries to include in the ZIP archive. Can be byte[], Stream, file path, file URL, base64 string, ZipEntry objects, or arrays of these types", - UIHint = InputUIHints.MultiLine - )] - public Input Entries { get; set; } = null!; - - /// - /// The compression level for the Zip Entries. Default is Optimal - /// - [Input( - Description = "The compression level for the Zip Entries. Default is Optimal", - UIHint = InputUIHints.DropDown - )] - public Input CompressionLevel { get; set; } = new(System.IO.Compression.CompressionLevel.Optimal); - - /// - protected override async ValueTask ExecuteAsync(ActivityExecutionContext context) - { - var entriesInput = Entries.Get(context); - var resolver = context.GetRequiredService(); - var logger = context.GetRequiredService>(); - - var entries = ParseEntries(entriesInput); - - var zipStream = await CreateZipStreamFromEntries(entries, resolver, context, logger); - - Result.Set(context, zipStream); - } - - private static IEnumerable ParseEntries(object? entriesInput) - { - return entriesInput switch - { - null => [], - IEnumerable enumerable => enumerable, - Array array => array.Cast(), - _ => [entriesInput] - }; - } - - private async Task CreateZipStreamFromEntries( - IEnumerable entries, - IContentResolver resolver, - ActivityExecutionContext context, - ILogger logger) - { - var zipStream = new MemoryStream(); - - try - { - using var zipArchive = new ZipArchive(zipStream, ZipArchiveMode.Update, leaveOpen: true); - var entryIndex = 0; - - var compressionLevel = CompressionLevel.Get(context); - foreach (var entryContent in entries) - { - try - { - await ProcessZipEntry(entryContent, zipArchive, resolver, context, entryIndex, compressionLevel); - } - catch (Exception ex) - { - logger.LogWarning(ex, "Failed to add entry {EntryIndex} to ZIP archive. Reason: {ExceptionMessage}", - entryIndex, ex.Message); - } - entryIndex++; - } - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to create ZIP archive"); - await zipStream.DisposeAsync(); - throw; - } - - // Reset stream position for reading - zipStream.Position = 0; - return zipStream; - } - - /// - /// Processes a single zip entry and adds it to the archive. - /// - private static async Task ProcessZipEntry( - object entryContent, - ZipArchive zipArchive, - IContentResolver resolver, - ActivityExecutionContext context, - int entryIndex, - CompressionLevel compressionLevel) - { - var binaryContent = await resolver.ResolveAsync(entryContent, context.CancellationToken); - - var entryName = binaryContent.Name?.GetNameAndExtension() - ?? string.Format(DefaultEntryNameFormat, entryIndex + 1); - - // Get a unique name following Windows convention - entryName = GetUniqueEntryName(zipArchive, entryName); - - var archiveEntry = zipArchive.CreateEntry(entryName, compressionLevel); - - await using var entryStream = archiveEntry.Open(); - await binaryContent.Stream.CopyToAsync(entryStream, context.CancellationToken); - await entryStream.FlushAsync(context.CancellationToken); - - if (entryContent is not Stream) - { - await binaryContent.Stream.DisposeAsync(); - } - } - - private static string GetUniqueEntryName(ZipArchive zipArchive, string originalName) - { - var filenameWithoutExtension = Path.GetFileNameWithoutExtension(originalName); - var extension = Path.GetExtension(originalName); - - var originalExists = false; - var highestIndex = 0; - - foreach (var entry in zipArchive.Entries) - { - if (!entry.Name.Equals(originalName, StringComparison.OrdinalIgnoreCase)) - { - continue; - } - - originalExists = true; - - var entryNameWithoutExtension = Path.GetFileNameWithoutExtension(entry.Name); - var entryExtension = Path.GetExtension(entry.Name); - - // Only process entries with the same extension - if (!entryExtension.Equals(extension, StringComparison.OrdinalIgnoreCase)) - continue; - - // Check if this entry follows our naming pattern - highestIndex = HighestEntryNameIndex(entryNameWithoutExtension, filenameWithoutExtension, highestIndex); - } - - if (!originalExists) - { - return originalName; - } - - return $"{filenameWithoutExtension}({highestIndex + 1}){extension}"; - } - - private static int HighestEntryNameIndex(string entryNameWithoutExtension, string filenameWithoutExtension, - int highestIndex) - { - if (!entryNameWithoutExtension.StartsWith(filenameWithoutExtension, StringComparison.OrdinalIgnoreCase) || - entryNameWithoutExtension.Length <= filenameWithoutExtension.Length || - entryNameWithoutExtension[filenameWithoutExtension.Length] != '(') - { - return highestIndex; - } - - // Extract the number between parentheses - var closingParenIndex = entryNameWithoutExtension.LastIndexOf(')'); - if (closingParenIndex <= filenameWithoutExtension.Length + 1) - { - return highestIndex; - } - - var indexStr = entryNameWithoutExtension.Substring( - filenameWithoutExtension.Length + 1, - closingParenIndex - filenameWithoutExtension.Length - 1); - - if (int.TryParse(indexStr, out var index)) - { - highestIndex = Math.Max(highestIndex, index); - } - - return highestIndex; - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO.Compression/Common/Constants.cs b/src/modules/Elsa.IO.Compression/Common/Constants.cs deleted file mode 100644 index f9e7a627e..000000000 --- a/src/modules/Elsa.IO.Compression/Common/Constants.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Elsa.IO.Compression.Common; - -public static class Constants -{ - public const float ZipEntryStrategyPriority = 0.5f; -} \ No newline at end of file diff --git a/src/modules/Elsa.IO.Compression/Elsa.IO.Compression.csproj b/src/modules/Elsa.IO.Compression/Elsa.IO.Compression.csproj deleted file mode 100644 index f1b1d9145..000000000 --- a/src/modules/Elsa.IO.Compression/Elsa.IO.Compression.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - - Provides compression and archiving activities for Elsa Workflows. - - elsa module compression zip archive workflows - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/modules/Elsa.IO.Compression/Extensions/ModuleExtensions.cs b/src/modules/Elsa.IO.Compression/Extensions/ModuleExtensions.cs deleted file mode 100644 index e471e4c49..000000000 --- a/src/modules/Elsa.IO.Compression/Extensions/ModuleExtensions.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Elsa.IO.Compression.Features; -using Elsa.Features.Services; - -// ReSharper disable once CheckNamespace -namespace Elsa.Extensions; - -/// -/// Provides extensions to install the feature. -/// -public static class ModuleExtensions -{ - /// - /// Install the feature. - /// - public static IModule UseCompression(this IModule module, Action? configure = default) - { - module.Configure(configure); - return module; - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO.Compression/Features/CompressionFeature.cs b/src/modules/Elsa.IO.Compression/Features/CompressionFeature.cs deleted file mode 100644 index 04bfb6ce4..000000000 --- a/src/modules/Elsa.IO.Compression/Features/CompressionFeature.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Elsa.Extensions; -using Elsa.Features.Abstractions; -using Elsa.Features.Attributes; -using Elsa.Features.Services; -using Elsa.IO.Compression.Models; -using Elsa.IO.Compression.Services.Strategies; -using Elsa.IO.Features; -using Elsa.IO.Services.Strategies; -using JetBrains.Annotations; -using Microsoft.Extensions.DependencyInjection; - -namespace Elsa.IO.Compression.Features; - -/// -/// Configures compression activities and services. -/// -[UsedImplicitly] -[DependsOn(typeof(IOFeature))] -public class CompressionFeature(IModule module) : FeatureBase(module) -{ - /// - public override void Configure() - { - Module.AddActivitiesFrom(); - Module.AddVariableTypeAndAlias("ZipEntry", "Compression"); - } - - /// - public override void Apply() - { - Services.AddScoped(); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO.Compression/FodyWeavers.xml b/src/modules/Elsa.IO.Compression/FodyWeavers.xml deleted file mode 100644 index 00e1d9a1c..000000000 --- a/src/modules/Elsa.IO.Compression/FodyWeavers.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/src/modules/Elsa.IO.Compression/Models/ZipEntry.cs b/src/modules/Elsa.IO.Compression/Models/ZipEntry.cs deleted file mode 100644 index 03986e6ce..000000000 --- a/src/modules/Elsa.IO.Compression/Models/ZipEntry.cs +++ /dev/null @@ -1,11 +0,0 @@ -using JetBrains.Annotations; - -namespace Elsa.IO.Compression.Models; - -/// -/// Represents a zip entry with content and metadata. -/// -/// The content of the zip entry. Can be byte[], Stream, file path, file URL, or base64 string. -/// The name of the entry in the zip archive. -[UsedImplicitly] -public record ZipEntry(object Content, string? EntryName = null); \ No newline at end of file diff --git a/src/modules/Elsa.IO.Compression/Services/Strategies/ZipEntryContentStrategy.cs b/src/modules/Elsa.IO.Compression/Services/Strategies/ZipEntryContentStrategy.cs deleted file mode 100644 index feaca88e0..000000000 --- a/src/modules/Elsa.IO.Compression/Services/Strategies/ZipEntryContentStrategy.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Elsa.IO.Compression.Common; -using Elsa.IO.Compression.Models; -using Elsa.IO.Contracts; -using Elsa.IO.Extensions; -using Elsa.IO.Models; -using Elsa.IO.Services.Strategies; -using Microsoft.Extensions.DependencyInjection; - -namespace Elsa.IO.Compression.Services.Strategies; - -/// -/// Strategy for resolving ZipEntry content with proper entry names. -/// -public class ZipEntryContentStrategy(IServiceProvider serviceProvider) : IContentResolverStrategy -{ - /// - public float Priority => Constants.ZipEntryStrategyPriority; - - /// - public bool CanResolve(object content) => content is ZipEntry; - - /// - public async Task ResolveAsync(object content, CancellationToken cancellationToken = default) - { - var zipEntry = (ZipEntry)content; - - var resolver = serviceProvider.GetRequiredService(); - - var innerContent = await resolver.ResolveAsync(zipEntry.Content, cancellationToken); - - if (string.IsNullOrEmpty(zipEntry.EntryName)) - { - return innerContent; - } - - var innerContentName = innerContent.Name?.GetNameAndExtension(); - var innerContentExtension = Path.GetExtension(innerContentName); - innerContent.Name = !string.IsNullOrWhiteSpace(innerContentExtension) - ? Path.HasExtension(zipEntry.EntryName) ? zipEntry.EntryName : zipEntry.EntryName + innerContentExtension - : innerContent.Name; - - return innerContent; - } -} diff --git a/src/modules/Elsa.IO.Http/Common/Constants.cs b/src/modules/Elsa.IO.Http/Common/Constants.cs deleted file mode 100644 index c785d5ee7..000000000 --- a/src/modules/Elsa.IO.Http/Common/Constants.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Elsa.IO.Http.Common; - -public static class Constants -{ - /// - /// The name of the HTTP client used for IO operations. - /// - public const string IOFeatureHttpClient = "IOFeatureHttpClient"; - - public static class StrategyPriorities - { - public const float Uri = 2.5f; - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO.Http/Elsa.IO.Http.csproj b/src/modules/Elsa.IO.Http/Elsa.IO.Http.csproj deleted file mode 100644 index eca9c5e79..000000000 --- a/src/modules/Elsa.IO.Http/Elsa.IO.Http.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Provides http capabilities to IO modules in Elsa Workflows. - - elsa module io http - - - - - - - - - - - - - - diff --git a/src/modules/Elsa.IO.Http/Features/IOHttpFeature.cs b/src/modules/Elsa.IO.Http/Features/IOHttpFeature.cs deleted file mode 100644 index 90916619f..000000000 --- a/src/modules/Elsa.IO.Http/Features/IOHttpFeature.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Elsa.Features.Abstractions; -using Elsa.Features.Attributes; -using Elsa.Features.Services; -using Elsa.IO.Compression.Features; -using Elsa.IO.Features; -using Elsa.IO.Http.Common; -using Elsa.IO.Http.Services.Strategies; -using Elsa.IO.Services.Strategies; -using JetBrains.Annotations; -using Microsoft.Extensions.DependencyInjection; - -namespace Elsa.IO.Http.Features; - -/// -/// Configures HTTP-based IO services. -/// -[UsedImplicitly] -[DependsOn(typeof(IOFeature))] -[DependencyOf(typeof(CompressionFeature))] -public class IOHttpFeature(IModule module) : FeatureBase(module) -{ - /// - public override void Apply() - { - Services.AddHttpClient(Constants.IOFeatureHttpClient); - - Services.AddScoped(); - } -} diff --git a/src/modules/Elsa.IO.Http/FodyWeavers.xml b/src/modules/Elsa.IO.Http/FodyWeavers.xml deleted file mode 100644 index 00e1d9a1c..000000000 --- a/src/modules/Elsa.IO.Http/FodyWeavers.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/src/modules/Elsa.IO.Http/Services/Strategies/UrlContentStrategy.cs b/src/modules/Elsa.IO.Http/Services/Strategies/UrlContentStrategy.cs deleted file mode 100644 index 5aece7553..000000000 --- a/src/modules/Elsa.IO.Http/Services/Strategies/UrlContentStrategy.cs +++ /dev/null @@ -1,78 +0,0 @@ -using Elsa.Extensions; -using Elsa.IO.Extensions; -using Elsa.IO.Http.Common; -using Elsa.IO.Models; -using Elsa.IO.Services.Strategies; -using Microsoft.Extensions.Logging; - -namespace Elsa.IO.Http.Services.Strategies; - -/// -/// Strategy for handling URL content by downloading from HTTP/HTTPS URLs. -/// -public class UrlContentStrategy(ILogger logger, IHttpClientFactory httpClientFactory) : IContentResolverStrategy -{ - /// - public float Priority => Constants.StrategyPriorities.Uri; - - /// - public bool CanResolve(object content) => content is string str && (str.StartsWith("http://") || str.StartsWith("https://")); - - /// - public async Task ResolveAsync(object content, CancellationToken cancellationToken = default) - { - var url = (string)content; - - try - { - var httpClient = httpClientFactory.CreateClient(); - var response = await httpClient.GetAsync(url, cancellationToken); - response.EnsureSuccessStatusCode(); - - var stream = await response.Content.ReadAsStreamAsync(cancellationToken); - var filename = ExtractFilenameFromResponse(response, url); - var contentType = response.Content.Headers.ContentType?.MediaType; - - return new BinaryContent - { - Name = filename.GetNameAndExtension(contentType.GetExtensionFromContentType()), - Stream = stream - }; - } - catch (Exception ex) - { - logger.LogError(ex, "Failed to download file from URL: {Url}", url); - throw; - } - } - - /// - /// Extracts a filename from the HTTP response, either from Content-Disposition header or URL. - /// - private string ExtractFilenameFromResponse(HttpResponseMessage response, string url) - { - var filename = response.GetFilename(); - if (!string.IsNullOrWhiteSpace(filename)) - { - return filename; - } - - try - { - var uri = new Uri(url); - var path = uri.AbsolutePath; - filename = Path.GetFileName(path); - - if (!string.IsNullOrEmpty(filename) && Path.HasExtension(filename)) - { - return filename; - } - } - catch (Exception ex) - { - logger.LogDebug(ex, "Failed to extract filename from URL: {Url}", url); - } - - return "download"; - } -} diff --git a/src/modules/Elsa.IO/Common/Constants.cs b/src/modules/Elsa.IO/Common/Constants.cs deleted file mode 100644 index 6444fc89c..000000000 --- a/src/modules/Elsa.IO/Common/Constants.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Elsa.IO.Common; - -/// -/// IO module constants. -/// -public static class Constants -{ - /// - /// Priorities for content resolver strategies. - /// - public static class StrategyPriorities - { - /// - /// Stream content priority. - /// - public const float Stream = 0.0f; - - /// - /// Byte array content priority. - /// - public const float ByteArray = 1.0f; - - /// - /// Base64 content priority. - /// - public const float Base64 = 2.0f; - - /// - /// File path content priority. - /// - public const float FilePath = 3.0f; - - /// - /// Text content priority. - /// - public const float Text = 100.0f; - } -} diff --git a/src/modules/Elsa.IO/Contracts/IContentResolver.cs b/src/modules/Elsa.IO/Contracts/IContentResolver.cs deleted file mode 100644 index 1ae60ca14..000000000 --- a/src/modules/Elsa.IO/Contracts/IContentResolver.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Elsa.IO.Contracts; - -using Elsa.IO.Models; - -/// -/// Provides methods to resolve various content types to BinaryContent. -/// -public interface IContentResolver -{ - /// - /// Resolves arbitrary content to a BinaryContent object that includes the content stream and metadata. - /// - /// The content to resolve. Can be byte[], Stream, file path, file URL, base64 string, or plain text. - /// A cancellation token. - /// A BinaryContent object containing the content stream and associated metadata. - Task ResolveAsync(object content, CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/Elsa.IO.csproj b/src/modules/Elsa.IO/Elsa.IO.csproj deleted file mode 100644 index f7dc3b034..000000000 --- a/src/modules/Elsa.IO/Elsa.IO.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - Provides IO services for resolving various content types to streams. - - elsa module io content streams - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/modules/Elsa.IO/Extensions/ContentTypeExtensions.cs b/src/modules/Elsa.IO/Extensions/ContentTypeExtensions.cs deleted file mode 100644 index 45bf158ef..000000000 --- a/src/modules/Elsa.IO/Extensions/ContentTypeExtensions.cs +++ /dev/null @@ -1,166 +0,0 @@ -namespace Elsa.IO.Extensions; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -public static class ContentTypeExtensions -{ - private static readonly Dictionary MimeMapping = new(StringComparer.OrdinalIgnoreCase); - private static readonly Dictionary> ContentTypeToExtensionsMap = new(StringComparer.OrdinalIgnoreCase); - - static ContentTypeExtensions() - { - // Define all mappings in a single place - AddMapping(".txt", "text/plain"); - AddMapping(".html", "text/html"); - AddMapping(".htm", "text/html"); - AddMapping(".css", "text/css"); - AddMapping(".js", "application/javascript"); - AddMapping(".json", "application/json"); - AddMapping(".xml", "application/xml"); - AddMapping(".jpg", "image/jpeg"); - AddMapping(".jpeg", "image/jpeg"); - AddMapping(".png", "image/png"); - AddMapping(".gif", "image/gif"); - AddMapping(".svg", "image/svg+xml"); - AddMapping(".pdf", "application/pdf"); - AddMapping(".doc", "application/msword"); - AddMapping(".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document"); - AddMapping(".xls", "application/vnd.ms-excel"); - AddMapping(".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); - AddMapping(".ppt", "application/vnd.ms-powerpoint"); - AddMapping(".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation"); - AddMapping(".zip", "application/zip"); - AddMapping(".csv", "text/csv"); - } - private static void AddMapping(string extension, string contentType) - { - // Map extension to content type - MimeMapping[extension] = contentType; - // Map content type to extension(s) - if (!ContentTypeToExtensionsMap.TryGetValue(contentType, out var extensions)) - { - extensions = new(StringComparer.OrdinalIgnoreCase); - ContentTypeToExtensionsMap[contentType] = extensions; - } - - extensions.Add(extension); - } - public static string GetExtensionFromContentType(this string? contentType) - { - if (string.IsNullOrEmpty(contentType)) - return ".bin"; - - if (contentType.EndsWith("/pdf") || contentType == "application/pdf") - return ".pdf"; - - if (ContentTypeToExtensionsMap.TryGetValue(contentType, out var extensions) && extensions.Any()) - { - // Return the first extension for this content type - return extensions.First(); - } - - return DetermineExtensionFromMimeType(contentType); - } - public static string GetContentTypeFromExtension(this string filePath) - { - var extension = filePath.GetFileExtension(); - - return MimeMapping.GetValueOrDefault(extension, "application/octet-stream"); - } - - public static string GetNameAndExtension(this string fileName, string? extension = ".bin") - { - var currentExtension = fileName.GetFileExtension(); - if (!string.IsNullOrWhiteSpace(currentExtension)) - { - return fileName; - } - - return fileName + extension; - } - - public static string GetFileExtension(this string filePath) - { - return Path.GetExtension(filePath).ToLowerInvariant(); - } - - public static bool IsBase64String(this string s) - { - if (string.IsNullOrWhiteSpace(s)) - return false; - - s = s.Trim(); - - // Length must be divisible by 4 - if (s.Length % 4 != 0) - return false; - - // Check padding position and count - var paddingIndex = s.IndexOf('='); - - switch (paddingIndex) - { - // Padding cannot be at index 0 - case 0: - // Padding must be at the end - case > 0 when paddingIndex < s.Length - 2: - // All characters after first '=' must also be '=' - case > 0 when s[paddingIndex..].Any(c => c != '='): - return false; - } - - // Check for valid Base64 characters - for (var i = 0; i < paddingIndex; i++) - { - var c = s[i]; - var isValid = - c is >= 'A' and <= 'Z' || - c is >= 'a' and <= 'z' || - c is >= '0' and <= '9' || - c == '+' || c == '/'; - - if (!isValid) - return false; - } - - // Additional check for short strings that are just lowercase+numbers - // This catches "whatever" and similar false positives - if (s.Length <= 10 && s.All(c => char.IsLower(c) || char.IsDigit(c))) - return false; - - // Try actual decoding - try - { - _ = Convert.FromBase64String(s); - return true; - } - catch - { - return false; - } - } - - private static string DetermineExtensionFromMimeType(string mimeType) - { - if (mimeType.Contains("/pdf")) - return ".pdf"; - if (mimeType.Contains("image/")) - return ".img"; - if (mimeType.Contains("text/")) - return ".txt"; - if (mimeType.Contains("audio/")) - return ".audio"; - if (mimeType.Contains("video/")) - return ".video"; - - if (mimeType.StartsWith("file/") || mimeType.StartsWith("@file/")) - { - var extension = mimeType[(mimeType.IndexOf('/') + 1)..]; - if (!string.IsNullOrWhiteSpace(extension)) - return "." + extension; - } - - return ".bin"; - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/Extensions/FilePathExtensions.cs b/src/modules/Elsa.IO/Extensions/FilePathExtensions.cs deleted file mode 100644 index cb8456f57..000000000 --- a/src/modules/Elsa.IO/Extensions/FilePathExtensions.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Elsa.IO.Extensions; - -public static class FilePathExtensions -{ - public static string CleanFilePath(this string filePath) - { - // Clean up the path - trim quotes and whitespace that might come from copy-paste - filePath = filePath.Trim().Trim('"', '\''); - - // Replace backslashes with forward slashes on Unix/Mac systems - if (Path.DirectorySeparatorChar == '/') - { - filePath = filePath.Replace('\\', '/'); - } - - return filePath; - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/Extensions/ModuleExtensions.cs b/src/modules/Elsa.IO/Extensions/ModuleExtensions.cs deleted file mode 100644 index dcd9b4bb0..000000000 --- a/src/modules/Elsa.IO/Extensions/ModuleExtensions.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Elsa.Extensions; -using Elsa.Features.Services; -using Elsa.IO.Features; - -namespace Elsa.IO.Extensions; - -/// -/// Provides extension methods for configuring IO services. -/// -public static class ModuleExtensions -{ - /// - /// Installs the IO module. - /// - public static IModule UseIO(this IModule module, Action? configure = null) - { - return module.Use(configure); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/Features/IOFeature.cs b/src/modules/Elsa.IO/Features/IOFeature.cs deleted file mode 100644 index 52cb72312..000000000 --- a/src/modules/Elsa.IO/Features/IOFeature.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Elsa.Features.Abstractions; -using Elsa.Features.Services; -using Elsa.IO.Contracts; -using Elsa.IO.Services; -using Elsa.IO.Services.Strategies; -using Microsoft.Extensions.DependencyInjection; - -namespace Elsa.IO.Features; - -/// -/// A feature that installs IO services for resolving various content types to streams. -/// -public class IOFeature(IModule module) : FeatureBase(module) -{ - /// - public override void Apply() - { - Services.AddScoped(); - Services.AddScoped(); - Services.AddScoped(); - Services.AddScoped(); - Services.AddScoped(); - - Services.AddScoped(); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/FodyWeavers.xml b/src/modules/Elsa.IO/FodyWeavers.xml deleted file mode 100644 index 06ee72161..000000000 --- a/src/modules/Elsa.IO/FodyWeavers.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/modules/Elsa.IO/Models/BinaryContent.cs b/src/modules/Elsa.IO/Models/BinaryContent.cs deleted file mode 100644 index ba5c7d2b1..000000000 --- a/src/modules/Elsa.IO/Models/BinaryContent.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using Elsa.IO.Extensions; - -namespace Elsa.IO.Models; - -/// -/// Represents normalized binary content with metadata. -/// -public class BinaryContent -{ - /// - /// Gets or sets the name of the content. - /// - public string? Name { get; set; } - - /// - /// Gets the content type (MIME type) based on file extension. - /// - public string? ContentType => !string.IsNullOrWhiteSpace(Name) - ? Path.GetExtension(Name).GetContentTypeFromExtension() - : null; - - /// - /// Gets or sets optional metadata headers. - /// - public IDictionary Headers { get; set; } = new Dictionary(); - - /// - /// Gets or sets the content stream. - /// - public Stream Stream { get; init; } = null!; -} diff --git a/src/modules/Elsa.IO/Services/ContentResolver.cs b/src/modules/Elsa.IO/Services/ContentResolver.cs deleted file mode 100644 index 607bce68b..000000000 --- a/src/modules/Elsa.IO/Services/ContentResolver.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Elsa.IO.Contracts; -using Elsa.IO.Models; -using Elsa.IO.Services.Strategies; - -namespace Elsa.IO.Services; - -/// -/// Resolves various content types to BinaryContent using a strategy pattern. -/// -public class ContentResolver : IContentResolver -{ - private readonly IEnumerable _strategies; - - /// - /// Initializes a new instance of the class. - /// - public ContentResolver(IEnumerable strategies) - { - _strategies = strategies.OrderBy(s => s.Priority).ToList(); - } - - /// - public async Task ResolveAsync(object content, CancellationToken cancellationToken = default) - { - var strategy = _strategies.FirstOrDefault(s => s.CanResolve(content)); - - if (strategy == null) - { - throw new ArgumentException($"Unsupported content type: {content.GetType().Name}"); - } - - return await strategy.ResolveAsync(content, cancellationToken); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/Services/Strategies/Base64ContentStrategy.cs b/src/modules/Elsa.IO/Services/Strategies/Base64ContentStrategy.cs deleted file mode 100644 index 61e7bb39d..000000000 --- a/src/modules/Elsa.IO/Services/Strategies/Base64ContentStrategy.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Elsa.IO.Common; -using Elsa.IO.Extensions; -using Elsa.IO.Models; - -namespace Elsa.IO.Services.Strategies; - -/// -/// Strategy for handling base64 encoded content. -/// -public class Base64ContentStrategy : IContentResolverStrategy -{ - /// - public float Priority => Constants.StrategyPriorities.Base64; - - /// - public bool CanResolve(object content) - { - return content is string str && IsBase64String(str); - } - - /// - public Task ResolveAsync(object content, CancellationToken cancellationToken = default) - { - var str = content.ToString()!; - var extension = ".bin"; - string? name = null; - - if (IsUriDataBase64String(str)) - { - var dataUrlParts = str.Split(';'); - if (dataUrlParts.Length > 0 && dataUrlParts[0].StartsWith("data:")) - { - var contentType = dataUrlParts[0][5..]; - extension = contentType.GetExtensionFromContentType(); - - name = "data" + extension; - } - - str = str[(str.IndexOf("base64,", StringComparison.Ordinal) + 7)..]; - } - - var base64Bytes = Convert.FromBase64String(str); - var stream = new MemoryStream(base64Bytes); - - return Task.FromResult(new BinaryContent - { - Name = name?.GetNameAndExtension(extension) ?? "data.bin", - Stream = stream, - }); - } - - private static bool IsBase64String(string base64) - { - return IsUriDataBase64String(base64) - || base64.IsBase64String(); - } - - private static bool IsUriDataBase64String(string base64) - { - return base64.StartsWith("data:") && base64.Contains("base64"); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/Services/Strategies/ByteArrayContentStrategy.cs b/src/modules/Elsa.IO/Services/Strategies/ByteArrayContentStrategy.cs deleted file mode 100644 index 71b5f1658..000000000 --- a/src/modules/Elsa.IO/Services/Strategies/ByteArrayContentStrategy.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Elsa.IO.Common; -using Elsa.IO.Models; - -namespace Elsa.IO.Services.Strategies; - -/// -/// Strategy for handling byte array content. -/// -public class ByteArrayContentStrategy : IContentResolverStrategy -{ - /// - public float Priority => Constants.StrategyPriorities.ByteArray; - - /// - public bool CanResolve(object content) => content is byte[]; - - /// - public Task ResolveAsync(object content, CancellationToken cancellationToken = default) - { - var bytes = (byte[])content; - var stream = new MemoryStream(bytes); - - var result = new BinaryContent - { - Stream = stream, - Name = "data.bin", - }; - - return Task.FromResult(result); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/Services/Strategies/FilePathContentStrategy.cs b/src/modules/Elsa.IO/Services/Strategies/FilePathContentStrategy.cs deleted file mode 100644 index 5f974cccf..000000000 --- a/src/modules/Elsa.IO/Services/Strategies/FilePathContentStrategy.cs +++ /dev/null @@ -1,89 +0,0 @@ -using Elsa.IO.Common; -using Elsa.IO.Extensions; -using Elsa.IO.Models; - -namespace Elsa.IO.Services.Strategies; - -/// -/// Strategy for handling file path content by reading from the filesystem. -/// -public class FilePathContentStrategy : IContentResolverStrategy -{ - /// - public float Priority => Constants.StrategyPriorities.FilePath; - - /// - public bool CanResolve(object content) - { - if (content is not string filePath) - { - return false; - } - - filePath = filePath.CleanFilePath(); - - try - { - if (Path.IsPathRooted(filePath) && File.Exists(filePath)) - { - return true; - } - - var normalized = Path.GetFullPath(filePath); - if (File.Exists(normalized)) - { - return true; - } - - var combined = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), filePath)); - return File.Exists(combined); - } - catch (Exception) - { - return false; - } - } - - /// - public Task ResolveAsync(object content, CancellationToken cancellationToken = default) - { - try - { - var filePath = (string)content; - filePath = ResolveActualPath(filePath); - - var fileName = Path.GetFileName(filePath); - var fileStream = File.OpenRead(filePath); - - var result = new BinaryContent - { - Name = fileName.GetNameAndExtension(), - Stream = fileStream - }; - - return Task.FromResult(result); - } - catch (Exception ex) when (ex is not FileNotFoundException) - { - throw new FileNotFoundException($"Error opening file: {content}", content.ToString(), ex); - } - } - - private string ResolveActualPath(string filePath) - { - filePath = filePath.CleanFilePath(); - - if (Path.IsPathRooted(filePath) && File.Exists(filePath)) - return filePath; - - var normalized = Path.GetFullPath(filePath); - if (File.Exists(normalized)) - return normalized; - - var combined = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), filePath)); - if (File.Exists(combined)) - return combined; - - throw new FileNotFoundException($"Could not find file at path: {filePath}", filePath); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/Services/Strategies/IContentResolverStrategy.cs b/src/modules/Elsa.IO/Services/Strategies/IContentResolverStrategy.cs deleted file mode 100644 index 680ade5fb..000000000 --- a/src/modules/Elsa.IO/Services/Strategies/IContentResolverStrategy.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Elsa.IO.Services.Strategies; - -using Elsa.IO.Models; - -/// -/// Defines a strategy for resolving specific content types to BinaryContent. -/// -public interface IContentResolverStrategy -{ - /// - /// The priority of the strategy. - /// - float Priority { get; } - - /// - /// Determines if this strategy can handle the specified content. - /// - /// The content to check. - /// True if this strategy can handle the content, false otherwise. - bool CanResolve(object content); - - /// - /// Resolves the content to a BinaryContent object that includes the content stream and metadata. - /// - /// The content to resolve. - /// A cancellation token. - /// A BinaryContent object containing the content stream and associated metadata. - Task ResolveAsync(object content, CancellationToken cancellationToken = default); -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/Services/Strategies/StreamContentStrategy.cs b/src/modules/Elsa.IO/Services/Strategies/StreamContentStrategy.cs deleted file mode 100644 index 538f7bcd7..000000000 --- a/src/modules/Elsa.IO/Services/Strategies/StreamContentStrategy.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Elsa.IO.Common; -using Elsa.IO.Extensions; -using Elsa.IO.Models; - -namespace Elsa.IO.Services.Strategies; - -/// -/// Strategy for handling Stream content. -/// -public class StreamContentStrategy : IContentResolverStrategy -{ - /// - public float Priority => Constants.StrategyPriorities.Stream; - - /// - public bool CanResolve(object content) => content is Stream; - - /// - public Task ResolveAsync(object content, CancellationToken cancellationToken = default) - { - var stream = (Stream)content; - - string? name = null; - if (stream is FileStream fileStream) - { - name = Path.GetFileName(fileStream.Name); - } - - var result = new BinaryContent - { - Stream = stream, - Name = name?.GetNameAndExtension() ?? "data.bin", - }; - - return Task.FromResult(result); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.IO/Services/Strategies/TextContentStrategy.cs b/src/modules/Elsa.IO/Services/Strategies/TextContentStrategy.cs deleted file mode 100644 index 23e5992b8..000000000 --- a/src/modules/Elsa.IO/Services/Strategies/TextContentStrategy.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Text; -using Elsa.IO.Common; -using Elsa.IO.Models; - -namespace Elsa.IO.Services.Strategies; - -/// -/// Strategy for handling plain text content by encoding as UTF-8. -/// -public class TextContentStrategy : IContentResolverStrategy -{ - /// - public float Priority => Constants.StrategyPriorities.Text; - - /// - public bool CanResolve(object content) => content is string; - - /// - public Task ResolveAsync(object content, CancellationToken cancellationToken = default) - { - var textContent = (string)content; - var textBytes = Encoding.UTF8.GetBytes(textContent); - var stream = new MemoryStream(textBytes); - - return Task.FromResult(new BinaryContent - { - Name = "text.txt", - Stream = stream - }); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.MongoDb/HostedServices/ConfigureMongoDbSerializers.cs b/src/modules/Elsa.MongoDb/HostedServices/ConfigureMongoDbSerializers.cs deleted file mode 100644 index 927bc81b0..000000000 --- a/src/modules/Elsa.MongoDb/HostedServices/ConfigureMongoDbSerializers.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Nodes; -using Elsa.MongoDb.Serializers; -using Elsa.Workflows; -using Elsa.Workflows.Activities.Flowchart.Models; -using Elsa.Workflows.Memory; -using JetBrains.Annotations; -using Microsoft.Extensions.Hosting; -using MongoDB.Bson.Serialization.Serializers; -using static MongoDB.Bson.Serialization.BsonSerializer; - -namespace Elsa.MongoDb.HostedServices; - -/// -/// A hosted service that configures and registers custom MongoDB serializers for various types. -/// -/// -/// This class implements and is responsible for registering serializers to handle -/// specific types such as , , , , -/// , , and . -/// It uses helper methods to register these serializers during the application's startup process. -/// -[UsedImplicitly] -public class ConfigureMongoDbSerializers(IPayloadSerializer payloadSerializer) : IHostedService -{ - public Task StartAsync(CancellationToken cancellationToken) - { - TryRegisterSerializer(typeof(object), new PolymorphicSerializer()); - TryRegisterSerializer(typeof(Type), new TypeSerializer()); - TryRegisterSerializer(typeof(Variable), new VariableSerializer()); - TryRegisterSerializer(typeof(Version), new VersionSerializer()); - TryRegisterSerializer(typeof(JsonElement), new JsonElementSerializer()); - TryRegisterSerializer(typeof(JsonNode), new JsonNodeBsonConverter()); - TryRegisterSerializer(typeof(FlowScope), new FlowScopeSerializer(payloadSerializer)); - - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } -} \ No newline at end of file diff --git a/src/modules/Elsa.MongoDb/Serializers/FlowScopeSerializer.cs b/src/modules/Elsa.MongoDb/Serializers/FlowScopeSerializer.cs deleted file mode 100644 index f6d78e931..000000000 --- a/src/modules/Elsa.MongoDb/Serializers/FlowScopeSerializer.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Elsa.Workflows; -using Elsa.Workflows.Activities.Flowchart.Models; -using MongoDB.Bson; -using MongoDB.Bson.Serialization; - -namespace Elsa.MongoDb.Serializers; - -/// -/// Serializes a . -/// -public class FlowScopeSerializer(IPayloadSerializer payloadSerializer) : IBsonSerializer -{ - /// - public Type ValueType => typeof(FlowScope); - - void IBsonSerializer.Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value) => Serialize(context, args, (FlowScope)value); - object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) => Deserialize(context, args); - - /// - public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, FlowScope? value) - { - if (value is null) - context.Writer.WriteNull(); - else - { - var json = payloadSerializer.Serialize(value); - context.Writer.WriteString(json); - } - } - - /// - public FlowScope Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) - { - var reader = context.Reader; - var bsonType = reader.GetCurrentBsonType(); - - if (bsonType == BsonType.Null) - { - reader.ReadNull(); - return new(); - } - - if(bsonType == BsonType.String) - { - var json = context.Reader.ReadString(); - - return string.IsNullOrEmpty(json) ? new() : payloadSerializer.Deserialize(json); - } - - return new(); - } -} \ No newline at end of file diff --git a/src/modules/Elsa.Workflows.Runtime.ProtoActor/Extensions/ProtoOutputExtensions.cs b/src/modules/Elsa.Workflows.Runtime.ProtoActor/Extensions/ProtoOutputExtensions.cs deleted file mode 100644 index b731d3fd7..000000000 --- a/src/modules/Elsa.Workflows.Runtime.ProtoActor/Extensions/ProtoOutputExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Elsa.Workflows.Runtime.ProtoActor.ProtoBuf; - -namespace Elsa.Workflows.Runtime.ProtoActor.Extensions; - -internal static class ProtoOutputExtensions -{ - public static IDictionary DeserializeOutput(this Output output) => output.Data.Deserialize(); - - public static Output SerializeOutput(this IDictionary output) - { - var result = new Output(); - output.Serialize(result.Data); - return result; - } -}