Refactor domain model and exception handling
Significantly restructured the `DigitalData.MessagingService.Domain` project by removing unused domain-specific classes, enums, and value objects. Key changes include: - Updated `ExceptionHandlingMiddleware` to handle `FluentValidation.ValidationException` with formatted validation errors mapped to `HttpStatusCode.BadRequest`. - Removed foundational domain classes such as `BaseEntity`, `ValueObject`, and `IAggregateRoot`. - Deleted enums (`AttachmentStatus`, `AuthenticationType`, `EmailStatus`, `ErrorCode`, `ProcessType`) and domain exceptions (`DomainException`, `AttachmentProcessingException`, `DmsNotAvailableException`, `InvalidPdfException`, `ValidationException`). - Removed value objects (`EmailAddress`, `MessageId`) and the `MessageIdGenerator` service. - Cleaned up the project structure by removing the `Events` folder reference. These changes simplify the domain model, reduce unused code, and align the project with updated architectural goals.
This commit is contained in:
@@ -48,13 +48,7 @@ public class ExceptionHandlingMiddleware
|
|||||||
|
|
||||||
AuthenticationFailedException authEx =>
|
AuthenticationFailedException authEx =>
|
||||||
(HttpStatusCode.Unauthorized, authEx.Message),
|
(HttpStatusCode.Unauthorized, authEx.Message),
|
||||||
|
|
||||||
DmsNotAvailableException dmsEx =>
|
|
||||||
(HttpStatusCode.ServiceUnavailable, dmsEx.Message),
|
|
||||||
|
|
||||||
InvalidPdfException pdfEx =>
|
|
||||||
(HttpStatusCode.BadRequest, pdfEx.Message),
|
|
||||||
|
|
||||||
FluentValidation.ValidationException validationEx =>
|
FluentValidation.ValidationException validationEx =>
|
||||||
(HttpStatusCode.BadRequest, FormatValidationErrors(validationEx)),
|
(HttpStatusCode.BadRequest, FormatValidationErrors(validationEx)),
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Common;
|
|
||||||
|
|
||||||
public abstract class BaseEntity
|
|
||||||
{
|
|
||||||
public DateTime? CreatedDate { get; set; }
|
|
||||||
public string? CreatedBy { get; set; }
|
|
||||||
public DateTime? ModifiedDate { get; set; }
|
|
||||||
public string? ModifiedBy { get; set; }
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Common;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Domain-wide constants
|
|
||||||
/// </summary>
|
|
||||||
public static class DomainConstants
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Email processing constants
|
|
||||||
/// </summary>
|
|
||||||
public static class Email
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Maximum number of retry attempts for failed email sending
|
|
||||||
/// After this limit, email will be moved to Dead Letter Queue (DLQ)
|
|
||||||
/// </summary>
|
|
||||||
public const int MaxRetryCount = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Common;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Marker interface for aggregate roots in DDD
|
|
||||||
/// </summary>
|
|
||||||
public interface IAggregateRoot
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Common;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base class for value objects that implement equality by value
|
|
||||||
/// </summary>
|
|
||||||
public abstract class ValueObject
|
|
||||||
{
|
|
||||||
protected abstract IEnumerable<object> GetEqualityComponents();
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != GetType())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var other = (ValueObject)obj;
|
|
||||||
return GetEqualityComponents().SequenceEqual(other.GetEqualityComponents());
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
return GetEqualityComponents()
|
|
||||||
.Select(x => x?.GetHashCode() ?? 0)
|
|
||||||
.Aggregate((x, y) => x ^ y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator ==(ValueObject? left, ValueObject? right)
|
|
||||||
{
|
|
||||||
if (left is null && right is null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (left is null || right is null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return left.Equals(right);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool operator !=(ValueObject? left, ValueObject? right)
|
|
||||||
{
|
|
||||||
return !(left == right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,8 +10,4 @@
|
|||||||
<PackageReference Include="MediatR" Version="12.2.0" />
|
<PackageReference Include="MediatR" Version="12.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Events\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Enums;
|
|
||||||
|
|
||||||
public enum AttachmentStatus
|
|
||||||
{
|
|
||||||
Pending = 1,
|
|
||||||
Valid = 2,
|
|
||||||
Corrupt = 3,
|
|
||||||
Skipped = 4
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Enums;
|
|
||||||
|
|
||||||
public enum AuthenticationType
|
|
||||||
{
|
|
||||||
UsernamePassword = 1,
|
|
||||||
OAuth2 = 2
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Enums;
|
|
||||||
|
|
||||||
public enum EmailStatus
|
|
||||||
{
|
|
||||||
Pending = 1,
|
|
||||||
Processing = 2,
|
|
||||||
Processed = 3,
|
|
||||||
Failed = 4,
|
|
||||||
PartiallyProcessed = 5,
|
|
||||||
Rejected = 6
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Enums;
|
|
||||||
|
|
||||||
public enum ErrorCode
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
NoAttachments = 10001,
|
|
||||||
SenderValidationFailed = 10002,
|
|
||||||
EmbeddedFileAttachmentCorrupt = 10003,
|
|
||||||
NormalFileAttachmentCorrupt = 10004,
|
|
||||||
PdfStructureInvalid = 10005,
|
|
||||||
ImapConnectionFailed = 10006,
|
|
||||||
WindreamImportFailed = 10007,
|
|
||||||
DiskSpaceInsufficient = 10008,
|
|
||||||
DuplicateMessageId = 10009,
|
|
||||||
AttachmentExtractionFailed = 10010
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Enums;
|
|
||||||
|
|
||||||
public enum ProcessType
|
|
||||||
{
|
|
||||||
ProcessManager = 1, // Easy Approval workflow
|
|
||||||
AttachmentSniffer = 2, // General attachment extraction
|
|
||||||
ZugFeRDParser = 3 // Electronic invoice processing
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using DigitalData.MessagingService.Domain.Enums;
|
|
||||||
|
|
||||||
namespace DigitalData.MessagingService.Domain.Exceptions;
|
|
||||||
|
|
||||||
public class AttachmentProcessingException : DomainException
|
|
||||||
{
|
|
||||||
public AttachmentProcessingException(ErrorCode errorCode, string message) : base(message, errorCode)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttachmentProcessingException(ErrorCode errorCode, string message, Exception innerException)
|
|
||||||
: base(message, errorCode)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Exceptions;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Exception thrown when DMS (windream) is not available or not configured properly.
|
|
||||||
/// </summary>
|
|
||||||
public class DmsNotAvailableException : Exception
|
|
||||||
{
|
|
||||||
public DmsNotAvailableException()
|
|
||||||
: base("DMS service is not available. windream COM components may not be registered.")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DmsNotAvailableException(string message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DmsNotAvailableException(string message, Exception innerException)
|
|
||||||
: base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using DigitalData.MessagingService.Domain.Enums;
|
|
||||||
|
|
||||||
namespace DigitalData.MessagingService.Domain.Exceptions;
|
|
||||||
|
|
||||||
public class DomainException : Exception
|
|
||||||
{
|
|
||||||
public ErrorCode? ErrorCode { get; }
|
|
||||||
|
|
||||||
public DomainException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public DomainException(string message, ErrorCode errorCode) : base(message)
|
|
||||||
{
|
|
||||||
ErrorCode = errorCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DomainException(string message, Exception innerException) : base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
namespace DigitalData.MessagingService.Domain.Exceptions;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Exception thrown when a PDF file is invalid or corrupted.
|
|
||||||
/// </summary>
|
|
||||||
public class InvalidPdfException : Exception
|
|
||||||
{
|
|
||||||
public InvalidPdfException(string message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public InvalidPdfException(string message, Exception innerException)
|
|
||||||
: base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using DigitalData.MessagingService.Domain.Enums;
|
|
||||||
|
|
||||||
namespace DigitalData.MessagingService.Domain.Exceptions;
|
|
||||||
|
|
||||||
public class ValidationException : DomainException
|
|
||||||
{
|
|
||||||
public ValidationException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValidationException(string message, ErrorCode errorCode) : base(message, errorCode)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValidationException(string message, Exception innerException) : base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
using DigitalData.MessagingService.Domain.ValueObjects;
|
|
||||||
|
|
||||||
namespace DigitalData.MessagingService.Domain.Services;
|
|
||||||
|
|
||||||
public interface IMessageIdGenerator
|
|
||||||
{
|
|
||||||
MessageId Generate(string originalMessageId, string sender, DateTime date, string subject);
|
|
||||||
List<string> GenerateFallbackHashes(MessageId messageId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class MessageIdGenerator : IMessageIdGenerator
|
|
||||||
{
|
|
||||||
public MessageId Generate(string originalMessageId, string sender, DateTime date, string subject)
|
|
||||||
{
|
|
||||||
return MessageId.Create(originalMessageId, sender, date, subject);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<string> GenerateFallbackHashes(MessageId messageId)
|
|
||||||
{
|
|
||||||
// Legacy behavior: 10 variations for duplicate detection
|
|
||||||
var hashes = new List<string> { messageId.Hash };
|
|
||||||
|
|
||||||
// Add variations (this is simplified - legacy had 10 variations)
|
|
||||||
// TODO: Implement exact legacy fallback algorithm if needed
|
|
||||||
|
|
||||||
return hashes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using DigitalData.MessagingService.Domain.Common;
|
|
||||||
using DigitalData.MessagingService.Domain.Exceptions;
|
|
||||||
|
|
||||||
namespace DigitalData.MessagingService.Domain.ValueObjects;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Value object representing an email address with validation
|
|
||||||
/// </summary>
|
|
||||||
public class EmailAddress : ValueObject
|
|
||||||
{
|
|
||||||
public string Value { get; private set; }
|
|
||||||
public string Domain { get; private set; }
|
|
||||||
public string LocalPart { get; private set; }
|
|
||||||
|
|
||||||
private EmailAddress(string value)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
var parts = value.Split('@');
|
|
||||||
LocalPart = parts[0];
|
|
||||||
Domain = parts[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EmailAddress Create(string email)
|
|
||||||
{
|
|
||||||
if (!IsValid(email))
|
|
||||||
throw new DomainException($"Invalid email address: {email}");
|
|
||||||
|
|
||||||
return new EmailAddress(email.ToLowerInvariant());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool IsValid(string email)
|
|
||||||
{
|
|
||||||
return !string.IsNullOrWhiteSpace(email) &&
|
|
||||||
email.Contains('@') &&
|
|
||||||
new EmailAddressAttribute().IsValid(email);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IEnumerable<object> GetEqualityComponents()
|
|
||||||
{
|
|
||||||
yield return Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() => Value;
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
using System.Security.Cryptography;
|
|
||||||
using System.Text;
|
|
||||||
using DigitalData.MessagingService.Domain.Common;
|
|
||||||
|
|
||||||
namespace DigitalData.MessagingService.Domain.ValueObjects;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Value object representing a unique message identifier with hash generation
|
|
||||||
/// Uses the same algorithm as legacy system for compatibility
|
|
||||||
/// </summary>
|
|
||||||
public class MessageId : ValueObject
|
|
||||||
{
|
|
||||||
public string Value { get; private set; }
|
|
||||||
public string Hash { get; private set; }
|
|
||||||
|
|
||||||
private MessageId(string value)
|
|
||||||
{
|
|
||||||
Value = value;
|
|
||||||
Hash = GenerateHash(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MessageId Create(string originalMessageId, string sender, DateTime date, string subject)
|
|
||||||
{
|
|
||||||
var combined = $"{originalMessageId}|{sender}|{date:yyyyMMddHHmmss}|{subject}";
|
|
||||||
return new MessageId(combined);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GenerateHash(string input)
|
|
||||||
{
|
|
||||||
// Same algorithm as legacy: SHA256 hash
|
|
||||||
using var sha256 = SHA256.Create();
|
|
||||||
var bytes = Encoding.UTF8.GetBytes(input);
|
|
||||||
var hash = sha256.ComputeHash(bytes);
|
|
||||||
return Convert.ToBase64String(hash);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override IEnumerable<object> GetEqualityComponents()
|
|
||||||
{
|
|
||||||
yield return Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user