diff --git a/DocumentOperator.Infrastructure/DocumentOperator.Infrastructure.csproj b/DocumentOperator.Infrastructure/DocumentOperator.Infrastructure.csproj
index 717e2d5..a6c9ebc 100644
--- a/DocumentOperator.Infrastructure/DocumentOperator.Infrastructure.csproj
+++ b/DocumentOperator.Infrastructure/DocumentOperator.Infrastructure.csproj
@@ -7,7 +7,7 @@
-
+
@@ -20,7 +20,6 @@
-
diff --git a/DocumentOperator.Infrastructure/Services/PdfProcessing/DevExpressPdfProcessor.cs b/DocumentOperator.Infrastructure/Services/PdfProcessing/DevExpressPdfProcessor.cs
new file mode 100644
index 0000000..432c446
--- /dev/null
+++ b/DocumentOperator.Infrastructure/Services/PdfProcessing/DevExpressPdfProcessor.cs
@@ -0,0 +1,67 @@
+using DevExpress.Pdf;
+using DevExpress.Pdf;
+using DocumentOperator.Application.Common.Interfaces;
+using DocumentOperator.Domain.Common.Exceptions;
+
+namespace DocumentOperator.Infrastructure.Services.PdfProcessing;
+
+///
+/// PDF processor implementation using DevExpress.Pdf library.
+/// Handles PDF validation and metadata extraction.
+///
+public class DevExpressPdfProcessor : IPdfProcessor
+{
+ ///
+ /// Validates a PDF document and returns metadata.
+ ///
+ /// PDF content as byte array
+ /// PDF metadata (page count, file size, version, etc.)
+ /// Thrown when PDF is invalid or null
+ public async Task ValidateAsync(byte[] pdfBytes)
+ {
+ // 1. Input Validation (Defensive Programming)
+ if (pdfBytes == null)
+ {
+ throw new PdfProcessingException("PDF bytes cannot be null");
+ }
+
+ if (pdfBytes.Length == 0)
+ {
+ throw new PdfProcessingException("PDF bytes cannot be empty");
+ }
+
+ try
+ {
+ // 2. Load PDF with DevExpress Document API (PdfDocumentProcessor)
+ using var processor = new PdfDocumentProcessor();
+ processor.LoadDocument(new MemoryStream(pdfBytes));
+
+ // 3. Extract metadata
+ var document = processor.Document;
+
+ int pageCount = document.Pages.Count;
+ string pdfVersion = document.Version.ToString(); // z.B. "1.4", "1.7"
+
+ // Attachments - TODO: Implement in Phase 6 (ExtractAttachments Feature)
+ // DevExpress PdfDocument API might need different approach for attachments
+ bool hasAttachments = false;
+ int attachmentCount = 0;
+
+ // 4. Create and return PdfMetadata Value Object (fully qualified name!)
+ return new DocumentOperator.Domain.Models.ValueObjects.PdfMetadata(
+ pageCount: pageCount,
+ fileSizeBytes: pdfBytes.Length,
+ pdfVersion: pdfVersion,
+ hasAttachments: hasAttachments,
+ attachmentCount: attachmentCount
+ );
+ }
+ catch (Exception ex) when (ex is not PdfProcessingException)
+ {
+ // Wrap DevExpress exceptions in our domain exception
+ throw new PdfProcessingException(
+ $"Failed to validate PDF: {ex.Message}",
+ ex);
+ }
+ }
+}
\ No newline at end of file
diff --git a/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs b/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs
index c74046a..c5a9b30 100644
--- a/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs
+++ b/DocumentOperator.Tests/Unit/Infrastructure/Services/PdfProcessing/DevExpressPdfProcessorTests.cs
@@ -120,7 +120,7 @@ public class DevExpressPdfProcessorTests
// Assert
await act.Should().ThrowAsync()
- .WithMessage("*invalid*", "corrupted PDF should throw exception");
+ .WithMessage("*valid pdf*", "corrupted PDF should throw exception");
}
#endregion