Add domain exceptions and update project structure

Implemented a structured exception-handling mechanism in the
domain layer with the addition of `DomainException`,
`DomainValidationException`, `NotFoundException`, and
`PdfProcessingException` classes. These exceptions provide
specific error handling for domain logic and integrate with
centralized middleware.

Updated `ROADMAP.md` to mark Step 2.1 (Domain Exceptions) as
completed and Step 2.2 (Value Objects) as the next task.
Added timeline entries to reflect progress.

Cleaned up `DocumentOperator.Domain.csproj` by removing
unused folder inclusions, indicating a project structure
reorganization.
This commit is contained in:
OlgunR
2026-06-16 16:38:19 +02:00
parent 5d3ec27128
commit d7c416256c
6 changed files with 123 additions and 10 deletions

View File

@@ -0,0 +1,25 @@
namespace DocumentOperator.Domain.Common.Exceptions;
/// <summary>
/// Base exception for all domain-related exceptions.
/// Caught by the Exception Handling Middleware in the API layer.
/// </summary>
public abstract class DomainException : Exception
{
/// <summary>
/// Error code for categorization and logging.
/// </summary>
public string ErrorCode { get; }
protected DomainException(string message, string errorCode)
: base(message)
{
ErrorCode = errorCode;
}
protected DomainException(string message, string errorCode, Exception innerException)
: base(message, innerException)
{
ErrorCode = errorCode;
}
}

View File

@@ -0,0 +1,28 @@
namespace DocumentOperator.Domain.Common.Exceptions;
/// <summary>
/// Exception thrown when domain validation fails (e.g., invalid Value Objects).
/// Maps to HTTP 400 Bad Request in the API layer.
/// </summary>
public class DomainValidationException : DomainException
{
public string PropertyName { get; }
public DomainValidationException(string message)
: base(message, "DOMAIN_VALIDATION_ERROR")
{
PropertyName = string.Empty;
}
public DomainValidationException(string propertyName, string message)
: base(message, "DOMAIN_VALIDATION_ERROR")
{
PropertyName = propertyName;
}
public DomainValidationException(string message, Exception innerException)
: base(message, "DOMAIN_VALIDATION_ERROR", innerException)
{
PropertyName = string.Empty;
}
}

View File

@@ -0,0 +1,25 @@
namespace DocumentOperator.Domain.Common.Exceptions;
/// <summary>
/// Exception thrown when a requested resource is not found.
/// Maps to HTTP 404 Not Found in the API layer.
/// </summary>
public class NotFoundException : DomainException
{
public string ResourceType { get; }
public object ResourceId { get; }
public NotFoundException(string resourceType, object resourceId)
: base($"{resourceType} with ID '{resourceId}' was not found.", "RESOURCE_NOT_FOUND")
{
ResourceType = resourceType;
ResourceId = resourceId;
}
public NotFoundException(string resourceType, object resourceId, string customMessage)
: base(customMessage, "RESOURCE_NOT_FOUND")
{
ResourceType = resourceType;
ResourceId = resourceId;
}
}

View File

@@ -0,0 +1,34 @@
namespace DocumentOperator.Domain.Common.Exceptions;
/// <summary>
/// Exception thrown when PDF processing operations fail.
/// Maps to HTTP 500 Internal Server Error or 422 Unprocessable Entity in the API layer.
/// </summary>
public class PdfProcessingException : DomainException
{
public string Operation { get; }
public PdfProcessingException(string operation, string message)
: base($"PDF processing failed during '{operation}': {message}", "PDF_PROCESSING_ERROR")
{
Operation = operation;
}
public PdfProcessingException(string operation, string message, Exception innerException)
: base($"PDF processing failed during '{operation}': {message}", "PDF_PROCESSING_ERROR", innerException)
{
Operation = operation;
}
public PdfProcessingException(string message)
: base(message, "PDF_PROCESSING_ERROR")
{
Operation = "Unknown";
}
public PdfProcessingException(string message, Exception innerException)
: base(message, "PDF_PROCESSING_ERROR", innerException)
{
Operation = "Unknown";
}
}

View File

@@ -7,7 +7,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Common\Exceptions\" />
<Folder Include="Common\Results\" /> <Folder Include="Common\Results\" />
<Folder Include="Constants\" /> <Folder Include="Constants\" />
<Folder Include="Models\Enums\" /> <Folder Include="Models\Enums\" />

View File

@@ -722,15 +722,15 @@ DocumentOperator.Domain/
--- ---
#### 🔄 Step 2.1: Domain Exceptions erstellen - **NEXT** #### Step 2.1: Domain Exceptions erstellen - **COMPLETED**
**Aufgabe:** Custom Exception-Klassen für fachliche Fehler **Aufgabe:** Custom Exception-Klassen für fachliche Fehler
**Zu erstellen:** **Erstellt:**
1. [ ] `DomainException.cs` (Basis-Exception) 1. [x] `DomainException.cs` (Basis-Exception)
2. [ ] `DomainValidationException.cs` (Value Object Validierung) 2. [x] `DomainValidationException.cs` (Value Object Validierung)
3. [ ] `NotFoundException.cs` (Resource nicht gefunden) 3. [x] `NotFoundException.cs` (Resource nicht gefunden)
4. [ ] `PdfProcessingException.cs` (PDF-spezifische Fehler) 4. [x] `PdfProcessingException.cs` (PDF-spezifische Fehler)
**Wo:** `Domain/Common/Exceptions/` **Wo:** `Domain/Common/Exceptions/`
@@ -755,7 +755,7 @@ if (notFound)
--- ---
#### Step 2.2: Value Objects erstellen #### 🔄 Step 2.2: Value Objects erstellen - **NEXT**
**Aufgabe:** Typsichere, selbst-validierende Wert-Objekte **Aufgabe:** Typsichere, selbst-validierende Wert-Objekte
@@ -1566,7 +1566,8 @@ Request mit X-API-Key → Middleware
### 🔄 In Progress ### 🔄 In Progress
- **Phase 2:** Domain Layer - **Phase 2:** Domain Layer
- **NEXT:** Step 2.1 - Domain Exceptions erstellen - Step 2.1 - Domain Exceptions
- **NEXT:** Step 2.2 - Value Objects
### ⏳ Pending ### ⏳ Pending
- Phase 3-9 - Phase 3-9
@@ -1629,7 +1630,8 @@ Request mit X-API-Key → Middleware
| 2024-XX-XX | Phase 1 | Configuration, Serilog, Options Pattern | | 2024-XX-XX | Phase 1 | Configuration, Serilog, Options Pattern |
| 2024-XX-XX | Phase 1 | **Decision:** Exception-based statt Ardalis.Result | | 2024-XX-XX | Phase 1 | **Decision:** Exception-based statt Ardalis.Result |
| 2024-XX-XX | Phase 1 | ✅ Phase 1 completed | | 2024-XX-XX | Phase 1 | ✅ Phase 1 completed |
| 2024-XX-XX | Phase 2 | 🔄 Starting Domain Layer - Exceptions | | 2024-XX-XX | Phase 2 | Step 2.1 completed - Domain Exceptions created |
| 2024-XX-XX | Phase 2 | 🔄 Starting Step 2.2 - Value Objects |
--- ---