diff --git a/src/modules/Elsa.EntityFrameworkCore.Common/Contracts/IDbExceptionHandler.cs b/src/modules/Elsa.EntityFrameworkCore.Common/Contracts/IDbExceptionHandler.cs new file mode 100644 index 000000000..78c8707fd --- /dev/null +++ b/src/modules/Elsa.EntityFrameworkCore.Common/Contracts/IDbExceptionHandler.cs @@ -0,0 +1,14 @@ +using Microsoft.EntityFrameworkCore; + +namespace Elsa.EntityFrameworkCore.Common.Contracts; + +/// Defines the contract for an exception handler in a database context. +/// +/// Implementing this interface allows for customized handling of exceptions that occur during database operations. +/// The parameter is used to be able to inject different ExceptionHandlers for each DbContext. +/// +public interface IDbExceptionHandler where TDbContext : DbContext +{ + /// Handles the given exception that occurs during database operations. + public void Handle(DbUpdateException exception); +} \ No newline at end of file diff --git a/src/modules/Elsa.EntityFrameworkCore.Common/EntityStore.cs b/src/modules/Elsa.EntityFrameworkCore.Common/EntityStore.cs index 794c139db..1097da421 100644 --- a/src/modules/Elsa.EntityFrameworkCore.Common/EntityStore.cs +++ b/src/modules/Elsa.EntityFrameworkCore.Common/EntityStore.cs @@ -1,4 +1,6 @@ using Elsa.Common.Entities; +using Elsa.EntityFrameworkCore.Common.Contracts; +using Microsoft.EntityFrameworkCore; namespace Elsa.EntityFrameworkCore.Common; @@ -7,13 +9,9 @@ namespace Elsa.EntityFrameworkCore.Common; /// /// The type of the database context. /// The type of the entity. -public class EntityStore : Store where TDbContext : ElsaDbContextBase where TEntity : Entity, new() +public class EntityStore(IDbContextFactory dbContextFactory, IDbExceptionHandler exceptionHandler) + : Store(dbContextFactory, exceptionHandler) where TDbContext : DbContext where TEntity : Entity, new() { - /// - public EntityStore(IServiceProvider serviceProvider) : base(serviceProvider) - { - } - /// /// Saves the entity. /// diff --git a/src/modules/Elsa.EntityFrameworkCore.Common/Store.cs b/src/modules/Elsa.EntityFrameworkCore.Common/Store.cs index a73f585d5..801aeaa89 100644 --- a/src/modules/Elsa.EntityFrameworkCore.Common/Store.cs +++ b/src/modules/Elsa.EntityFrameworkCore.Common/Store.cs @@ -1,5 +1,6 @@ using Elsa.Common.Entities; using Elsa.Common.Models; +using Elsa.EntityFrameworkCore.Common.Contracts; using Elsa.EntityFrameworkCore.Extensions; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; @@ -16,7 +17,7 @@ namespace Elsa.EntityFrameworkCore.Common; /// The type of the database context. /// The type of the entity. [PublicAPI] -public class Store where TDbContext : ElsaDbContextBase where TEntity : class, new() +public class Store(IDbContextFactory dbContextFactory, IDbExceptionHandler exceptionHandler) where TDbContext : DbContext where TEntity : class, new() { private readonly IServiceProvider _serviceProvider; @@ -24,28 +25,12 @@ public class Store where TDbContext : ElsaDbContextBase whe // Justification: This is a static member that is used to ensure that only one thread can access the database for TEntity at a time. private static readonly SemaphoreSlim Semaphore = new(1, 1); - /// - /// Initializes a new instance of the class. - /// - public Store(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - /// /// Creates a new instance of the database context. /// /// The cancellation token. /// The database context. - public async Task CreateDbContextAsync(CancellationToken cancellationToken = default) - { - var dbContextFactory = _serviceProvider.GetRequiredService>(); - var tenantResolver = _serviceProvider.GetRequiredService(); - var dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); - var tenant = await tenantResolver.GetTenantAsync(cancellationToken); - dbContext.TenantId = tenant?.Id; - return dbContext; - } + public async Task CreateDbContextAsync(CancellationToken cancellationToken = default) => await dbContextFactory.CreateDbContextAsync(cancellationToken); /// /// Adds the specified entity. @@ -142,6 +127,10 @@ public class Store where TDbContext : ElsaDbContextBase whe set.Entry(entity).State = exists ? EntityState.Modified : EntityState.Added; await dbContext.SaveChangesAsync(cancellationToken); } + catch (DbUpdateException ex) + { + exceptionHandler.Handle(ex); + } finally { Semaphore.Release(); @@ -178,7 +167,14 @@ public class Store where TDbContext : ElsaDbContextBase whe await Task.WhenAll(savingTasks); } - await dbContext.BulkUpsertAsync(entityList, keySelector, cancellationToken); + try + { + await dbContext.BulkUpsertAsync(entityList, keySelector, cancellationToken); + } + catch (DbUpdateException ex) + { + exceptionHandler.Handle(ex); + } } /// diff --git a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Features.cs b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Features.cs index 3bfee3284..064912eb0 100644 --- a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Features.cs +++ b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Features.cs @@ -5,6 +5,7 @@ using Elsa.EntityFrameworkCore.Modules.Identity; using Elsa.EntityFrameworkCore.Modules.Labels; using Elsa.EntityFrameworkCore.Modules.Management; using Elsa.EntityFrameworkCore.Modules.Runtime; +using Elsa.EntityFrameworkCore.PostgreSql.Handlers; // ReSharper disable once CheckNamespace namespace Elsa.EntityFrameworkCore.Extensions; @@ -22,6 +23,7 @@ public static class PostgreSqlProvidersExtensions public static EFCoreIdentityPersistenceFeature UsePostgreSql(this EFCoreIdentityPersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default) { feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options); + feature.DbExceptionHandler = _ => new DbExceptionHandler(); return feature; } @@ -31,6 +33,7 @@ public static class PostgreSqlProvidersExtensions public static EFCoreAlterationsPersistenceFeature UsePostgreSql(this EFCoreAlterationsPersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default) { feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options); + feature.DbExceptionHandler = _ => new DbExceptionHandler(); return feature; } @@ -40,6 +43,7 @@ public static class PostgreSqlProvidersExtensions public static EFCoreLabelPersistenceFeature UsePostgreSql(this EFCoreLabelPersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default) { feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options); + feature.DbExceptionHandler = _ => new DbExceptionHandler(); return feature; } @@ -49,6 +53,7 @@ public static class PostgreSqlProvidersExtensions public static EFCoreWorkflowDefinitionPersistenceFeature UsePostgreSql(this EFCoreWorkflowDefinitionPersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default) { feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options); + feature.DbExceptionHandler = _ => new DbExceptionHandler(); return feature; } @@ -58,6 +63,7 @@ public static class PostgreSqlProvidersExtensions public static EFCoreWorkflowInstancePersistenceFeature UsePostgreSql(this EFCoreWorkflowInstancePersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default) { feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options); + feature.DbExceptionHandler = _ => new DbExceptionHandler(); return feature; } @@ -67,6 +73,7 @@ public static class PostgreSqlProvidersExtensions public static WorkflowManagementPersistenceFeature UsePostgreSql(this WorkflowManagementPersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default) { feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options); + feature.DbExceptionHandler = _ => new DbExceptionHandler(); return feature; } @@ -76,6 +83,7 @@ public static class PostgreSqlProvidersExtensions public static EFCoreWorkflowRuntimePersistenceFeature UsePostgreSql(this EFCoreWorkflowRuntimePersistenceFeature feature, string connectionString, ElsaDbContextOptions? options = default) { feature.DbContextOptionsBuilder = (_, db) => db.UseElsaPostgreSql(Assembly, connectionString, options); + feature.DbExceptionHandler = _ => new DbExceptionHandler(); return feature; } } \ No newline at end of file diff --git a/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Handlers/DbExceptionHandler.cs b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Handlers/DbExceptionHandler.cs new file mode 100644 index 000000000..f23150beb --- /dev/null +++ b/src/modules/Elsa.EntityFrameworkCore.PostgreSql/Handlers/DbExceptionHandler.cs @@ -0,0 +1,29 @@ +using Elsa.EntityFrameworkCore.Common.Contracts; +using Elsa.EntityFrameworkCore.Modules.Alterations; +using Elsa.EntityFrameworkCore.Modules.Identity; +using Elsa.EntityFrameworkCore.Modules.Labels; +using Elsa.EntityFrameworkCore.Modules.Management; +using Elsa.EntityFrameworkCore.Modules.Runtime; +using Elsa.Workflows.Exceptions; +using Microsoft.EntityFrameworkCore; +using Npgsql; + +namespace Elsa.EntityFrameworkCore.PostgreSql.Handlers; + +/// +/// Handles database exceptions encountered when using a postgreSQL database. +/// +public class DbExceptionHandler : IDbExceptionHandler, + IDbExceptionHandler, + IDbExceptionHandler, + IDbExceptionHandler, + IDbExceptionHandler +{ + /// Handles database exceptions encountered when using a postgreSQL database. + public void Handle(DbUpdateException exception) + { + var ex = exception.InnerException as PostgresException; + + throw new DataProcessingException(ex?.SqlState == "23505", "Unable to save data", exception); + } +} \ No newline at end of file diff --git a/src/modules/Elsa.EntityFrameworkCore/Handlers/NoopDbExceptionHandler.cs b/src/modules/Elsa.EntityFrameworkCore/Handlers/NoopDbExceptionHandler.cs new file mode 100644 index 000000000..7fb04ecb7 --- /dev/null +++ b/src/modules/Elsa.EntityFrameworkCore/Handlers/NoopDbExceptionHandler.cs @@ -0,0 +1,23 @@ +using Elsa.EntityFrameworkCore.Common.Contracts; +using Elsa.EntityFrameworkCore.Modules.Alterations; +using Elsa.EntityFrameworkCore.Modules.Identity; +using Elsa.EntityFrameworkCore.Modules.Labels; +using Elsa.EntityFrameworkCore.Modules.Management; +using Elsa.EntityFrameworkCore.Modules.Runtime; +using Microsoft.EntityFrameworkCore; + +namespace Elsa.EntityFrameworkCore.Handlers; + +/// A No-Op database exception handler. +public class NoopDbExceptionHandler : IDbExceptionHandler, + IDbExceptionHandler, + IDbExceptionHandler, + IDbExceptionHandler, + IDbExceptionHandler +{ + /// Handles the given exception that occurs during database operations. + public void Handle(DbUpdateException exception) + { + throw exception; + } +} \ No newline at end of file diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Alterations/Feature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Alterations/Feature.cs index bf387b703..d27417ade 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Alterations/Feature.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Alterations/Feature.cs @@ -2,6 +2,7 @@ using Elsa.Alterations.Core.Entities; using Elsa.Alterations.Features; using Elsa.EntityFrameworkCore.Common; using Elsa.EntityFrameworkCore.Common.Contracts; +using Elsa.EntityFrameworkCore.Handlers; using Elsa.Features.Attributes; using Elsa.Features.Services; using Microsoft.Extensions.DependencyInjection; @@ -12,12 +13,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Alterations; /// Configures the default workflow runtime to use EF Core persistence providers. /// [DependsOn(typeof(AlterationsFeature))] -public class EFCoreAlterationsPersistenceFeature : PersistenceFeatureBase +public class EFCoreAlterationsPersistenceFeature(IModule module) : PersistenceFeatureBase(module) { - /// - public EFCoreAlterationsPersistenceFeature(IModule module) : base(module) - { - } + /// Delegate for determining the exception handler. + public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler(); /// public override void Configure() @@ -33,6 +32,7 @@ public class EFCoreAlterationsPersistenceFeature : PersistenceFeatureBase(); AddEntityStore(); diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Identity/Feature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Identity/Feature.cs index af6819c85..c370c89d8 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Identity/Feature.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Identity/Feature.cs @@ -1,4 +1,6 @@ using Elsa.EntityFrameworkCore.Common; +using Elsa.EntityFrameworkCore.Common.Contracts; +using Elsa.EntityFrameworkCore.Handlers; using Elsa.Features.Attributes; using Elsa.Features.Services; using Elsa.Identity.Entities; @@ -13,12 +15,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Identity; /// [DependsOn(typeof(IdentityFeature))] [PublicAPI] -public class EFCoreIdentityPersistenceFeature : PersistenceFeatureBase +public class EFCoreIdentityPersistenceFeature(IModule module) : PersistenceFeatureBase(module) { - /// - public EFCoreIdentityPersistenceFeature(IModule module) : base(module) - { - } + /// Delegate for determining the exception handler. + public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler(); /// public override void Configure() @@ -36,6 +36,8 @@ public class EFCoreIdentityPersistenceFeature : PersistenceFeatureBase(); AddEntityStore(); AddEntityStore(); diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Labels/Feature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Labels/Feature.cs index 54cfbaeb1..67819b067 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Labels/Feature.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Labels/Feature.cs @@ -1,4 +1,6 @@ using Elsa.EntityFrameworkCore.Common; +using Elsa.EntityFrameworkCore.Common.Contracts; +using Elsa.EntityFrameworkCore.Handlers; using Elsa.Extensions; using Elsa.Features.Attributes; using Elsa.Features.Services; @@ -12,9 +14,11 @@ namespace Elsa.EntityFrameworkCore.Modules.Labels; /// Configures the feature with an Entity Framework Core persistence provider. /// [DependsOn(typeof(LabelsFeature))] -public class EFCoreLabelPersistenceFeature(IModule module) : PersistenceFeatureBase(module) +public class EFCoreLabelPersistenceFeature(IModule module) : PersistenceFeatureBase(module) { - /// + /// Delegate for determining the exception handler. + public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler(); + public override void Configure() { Module.UseLabels(labels => @@ -29,6 +33,8 @@ public class EFCoreLabelPersistenceFeature(IModule module) : PersistenceFeatureB { base.Apply(); + Services.AddScoped(DbExceptionHandler); + AddEntityStore(); AddEntityStore(); } diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs index 9460c65f5..6c4a28c54 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowDefinitionPersistenceFeature.cs @@ -1,4 +1,6 @@ using Elsa.EntityFrameworkCore.Common; +using Elsa.EntityFrameworkCore.Common.Contracts; +using Elsa.EntityFrameworkCore.Handlers; using Elsa.Features.Attributes; using Elsa.Features.Services; using Elsa.Workflows.Management.Entities; @@ -11,12 +13,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Management; /// Configures the feature with an Entity Framework Core persistence provider. /// [DependsOn(typeof(WorkflowManagementFeature))] -public class EFCoreWorkflowDefinitionPersistenceFeature : PersistenceFeatureBase +public class EFCoreWorkflowDefinitionPersistenceFeature(IModule module) : PersistenceFeatureBase(module) { - /// - public EFCoreWorkflowDefinitionPersistenceFeature(IModule module) : base(module) - { - } + /// Delegate for determining the exception handler. + public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler(); /// public override void Configure() @@ -32,6 +32,8 @@ public class EFCoreWorkflowDefinitionPersistenceFeature : PersistenceFeatureBase { base.Apply(); + Services.AddScoped(DbExceptionHandler); + AddEntityStore(); } } \ No newline at end of file diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstancePersistenceFeature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstancePersistenceFeature.cs index 8461f2646..51b175e05 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstancePersistenceFeature.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowInstancePersistenceFeature.cs @@ -1,5 +1,6 @@ using Elsa.EntityFrameworkCore.Common; using Elsa.EntityFrameworkCore.Common.Contracts; +using Elsa.EntityFrameworkCore.Handlers; using Elsa.Features.Attributes; using Elsa.Features.Services; using Elsa.Workflows.Management.Entities; @@ -12,12 +13,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Management; /// Configures the feature with an Entity Framework Core persistence provider. /// [DependsOn(typeof(WorkflowManagementFeature))] -public class EFCoreWorkflowInstancePersistenceFeature : PersistenceFeatureBase +public class EFCoreWorkflowInstancePersistenceFeature(IModule module) : PersistenceFeatureBase(module) { - /// - public EFCoreWorkflowInstancePersistenceFeature(IModule module) : base(module) - { - } + /// Delegate for determining the exception handler. + public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler(); /// public override void Configure() @@ -30,6 +29,8 @@ public class EFCoreWorkflowInstancePersistenceFeature : PersistenceFeatureBase(); Services.AddScoped(); } diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowManagementPersistenceFeature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowManagementPersistenceFeature.cs index f9ae951f7..f73185bb7 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowManagementPersistenceFeature.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Management/WorkflowManagementPersistenceFeature.cs @@ -1,4 +1,6 @@ using Elsa.EntityFrameworkCore.Common; +using Elsa.EntityFrameworkCore.Common.Contracts; +using Elsa.EntityFrameworkCore.Handlers; using Elsa.Features.Attributes; using Elsa.Features.Services; using Elsa.Workflows.Management.Entities; @@ -15,12 +17,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Management; [DependsOn(typeof(WorkflowInstancesFeature))] [DependsOn(typeof(WorkflowDefinitionsFeature))] [PublicAPI] -public class WorkflowManagementPersistenceFeature : PersistenceFeatureBase +public class WorkflowManagementPersistenceFeature(IModule module) : PersistenceFeatureBase(module) { - /// - public WorkflowManagementPersistenceFeature(IModule module) : base(module) - { - } + /// Delegate for determining the exception handler. + public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler(); /// public override void Configure() @@ -34,6 +34,8 @@ public class WorkflowManagementPersistenceFeature : PersistenceFeatureBase(); AddEntityStore(); } diff --git a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs index 9ec996678..5ab7a0a57 100644 --- a/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs +++ b/src/modules/Elsa.EntityFrameworkCore/Modules/Runtime/WorkflowRuntimePersistenceFeature.cs @@ -1,5 +1,6 @@ using Elsa.EntityFrameworkCore.Common; using Elsa.EntityFrameworkCore.Common.Contracts; +using Elsa.EntityFrameworkCore.Handlers; using Elsa.Features.Attributes; using Elsa.Features.Services; using Elsa.KeyValues.Entities; @@ -14,12 +15,10 @@ namespace Elsa.EntityFrameworkCore.Modules.Runtime; /// Configures the default workflow runtime to use EF Core persistence providers. /// [DependsOn(typeof(WorkflowRuntimeFeature))] -public class EFCoreWorkflowRuntimePersistenceFeature : PersistenceFeatureBase +public class EFCoreWorkflowRuntimePersistenceFeature(IModule module) : PersistenceFeatureBase(module) { - /// - public EFCoreWorkflowRuntimePersistenceFeature(IModule module) : base(module) - { - } + /// Delegate for determining the exception handler. + public Func> DbExceptionHandler { get; set; } = _ => new NoopDbExceptionHandler(); /// public override void Configure() @@ -42,6 +41,8 @@ public class EFCoreWorkflowRuntimePersistenceFeature : PersistenceFeatureBase(); AddStore(); diff --git a/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs b/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs index 8871fd2f0..4e07d7a7a 100644 --- a/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs +++ b/src/modules/Elsa.Expressions/Helpers/ObjectConverter.cs @@ -112,7 +112,13 @@ public static class ObjectConverter if (underlyingSourceType == typeof(string) && !underlyingTargetType.IsPrimitive && underlyingTargetType != typeof(object)) { var stringValue = (string)value; - + + if (underlyingTargetType == typeof(byte[])) + { + // Byte arrays are serialized to base64, so in this case, we convert the string back to the requested target type of byte[]. + return Convert.FromBase64String(stringValue); + } + try { var firstChar = stringValue.TrimStart().FirstOrDefault(); diff --git a/src/modules/Elsa.MongoDb/Features/MongoDbFeature.cs b/src/modules/Elsa.MongoDb/Features/MongoDbFeature.cs index 65bdb406e..c32d42335 100644 --- a/src/modules/Elsa.MongoDb/Features/MongoDbFeature.cs +++ b/src/modules/Elsa.MongoDb/Features/MongoDbFeature.cs @@ -63,7 +63,7 @@ public class MongoDbFeature : FeatureBase cm.AutoMap(); // Automatically map other properties; }); - BsonClassMap.RegisterClassMap(map => + BsonClassMap.TryRegisterClassMap(map => { map.AutoMap(); map.SetIgnoreExtraElements(true); // Needed for missing ID property diff --git a/src/modules/Elsa.Scheduling/Activities/Delay.cs b/src/modules/Elsa.Scheduling/Activities/Delay.cs index 1c56d11ee..63981e03d 100644 --- a/src/modules/Elsa.Scheduling/Activities/Delay.cs +++ b/src/modules/Elsa.Scheduling/Activities/Delay.cs @@ -78,7 +78,7 @@ public class Delay : Activity, IActivityPropertyDefaultValueProvider var resumeAt = clock.UtcNow.Add(timeSpan); var payload = new DelayPayload(resumeAt); - context.JournalData.Add("ResumeAt", resumeAt); + context.JournalData["ResumeAt"] = resumeAt; context.CreateBookmark(payload); } diff --git a/src/modules/Elsa.Workflows.Core/Exceptions/DataProcessingException.cs b/src/modules/Elsa.Workflows.Core/Exceptions/DataProcessingException.cs new file mode 100644 index 000000000..2af7ab1e2 --- /dev/null +++ b/src/modules/Elsa.Workflows.Core/Exceptions/DataProcessingException.cs @@ -0,0 +1,8 @@ +namespace Elsa.Workflows.Exceptions; + +/// An exception that occurs during data processing. +public class DataProcessingException(bool isUkViolation, string message, Exception exception) : Exception(message, exception) +{ + /// Gets a value indicating whether the exception is a Unique Key violation. + public bool IsUkViolation { get; } = isUkViolation; +}