Files
DocumentService/DocumentService.Client
TekH 108e522316 Add multi-targeting and refactor project structure
Enabled multi-targeting in `DocumentService.Application` to support `net462`, `net480`, and `net8.0`. Updated dependencies with framework-specific versions and added conditional configurations for compatibility.

Refactored `DocumentService.Client` by removing redundant enums and unused code. Adjusted namespaces and project references to streamline the codebase and improve maintainability.

These changes modernize the project, enhance compatibility, and align with modular design principles.
2026-08-31 00:53:34 +02:00
..

DocumentService.Client

.NET client library for DocumentService API - supports .NET Framework 4.6.2, 4.8, and .NET 8.0.

Features

  • Multi-target support: .NET Framework 4.6.2, 4.8, and .NET 8.0
  • HttpClientFactory integration: Proper lifecycle management and connection pooling
  • Separate clients per controller: IPdfValidationClient, IPdfAttachmentClient, IPdfOperationsClient, ISwissQrCodeClient
  • Dual input support: Multipart (Stream) and Base64 (byte[]) for all endpoints
  • Strongly-typed models: Shared request/response DTOs with XML documentation

Installation

dotnet add package DocumentService.Client

Configuration

ASP.NET Core / .NET 8.0

using DocumentService.Client.Extensions;

var builder = WebApplication.CreateBuilder(args);

// Register all DocumentService clients
builder.Services.AddDocumentServiceClients(options =>
{
    options.BaseUrl = "https://documentservice.example.com";
    options.Timeout = TimeSpan.FromMinutes(10);
    options.MaxRetries = 3;
    options.ThrowOnError = true;
});

var app = builder.Build();

.NET Framework 4.6.2 / 4.8

using DocumentService.Client.Extensions;
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();

services.AddDocumentServiceClients(options =>
{
    options.BaseUrl = "https://documentservice.example.com";
    options.Timeout = TimeSpan.FromMinutes(10);
});

var serviceProvider = services.BuildServiceProvider();

Usage Examples

1. PDF Validation

using DocumentService.Client.Interfaces;

public class PdfService
{
    private readonly IPdfValidationClient _validationClient;

    public PdfService(IPdfValidationClient validationClient)
    {
        _validationClient = validationClient;
    }

    public async Task ValidatePdfAsync(Stream pdfStream)
    {
        // Option 1: From Stream (multipart)
        var result = await _validationClient.ValidatePdfAsync(pdfStream);
        
        Console.WriteLine($"Pages: {result.PageCount}");
        Console.WriteLine($"Version: {result.PdfVersion}");
        Console.WriteLine($"Encrypted: {result.IsEncrypted}");
    }

    public async Task ValidatePdfFromBytesAsync(byte[] pdfBytes)
    {
        // Option 2: From byte array (Base64 JSON)
        var result = await _validationClient.ValidatePdfAsync(pdfBytes);
        
        Console.WriteLine($"File Size: {result.FileSizeBytes} bytes");
    }

    public async Task ValidatePdfAAsync(string filePath)
    {
        using var stream = File.OpenRead(filePath);
        var result = await _validationClient.ValidatePdfAAsync(stream);
        
        Console.WriteLine($"Valid PDF/A: {result.IsValid}");
        Console.WriteLine($"PDF/A Version: {result.PdfAVersion}");
        
        if (result.Errors.Any())
        {
            Console.WriteLine("Errors:");
            foreach (var error in result.Errors)
            {
                Console.WriteLine($"  - {error}");
            }
        }
    }
}

2. PDF Attachments

using DocumentService.Client.Interfaces;
using DocumentService.Client.Extensions; // For ToBase64StringAsync, ToBytesAsync

public class AttachmentService
{
    private readonly IPdfAttachmentClient _attachmentClient;

    public AttachmentService(IPdfAttachmentClient attachmentClient)
    {
        _attachmentClient = attachmentClient;
    }

    public async Task CheckAttachmentsAsync(byte[] pdfBytes)
    {
        var result = await _attachmentClient.CheckAttachmentsAsync(pdfBytes);
        
        Console.WriteLine($"Has Attachments: {result.HasAttachments}");
        Console.WriteLine($"Attachment Count: {result.AttachmentCount}");
        
        foreach (var attachment in result.Attachments)
        {
            Console.WriteLine($"  - {attachment.FileName} ({attachment.Size} bytes)");
        }
    }

    public async Task ExtractAttachmentsAsync(Stream pdfStream, string outputPath)
    {
        // Returns ZIP file as Stream (memory efficient!)
        using var zipStream = await _attachmentClient.ExtractAttachmentsAsync(pdfStream);
        
        // Option 1: Save directly to file
        using var fileStream = File.Create(outputPath);
        await zipStream.CopyToAsync(fileStream);
        
        Console.WriteLine($"Attachments extracted to: {outputPath}");
    }

    public async Task ExtractAttachmentsToBase64Async(byte[] pdfBytes)
    {
        // Returns ZIP as Stream
        using var zipStream = await _attachmentClient.ExtractAttachmentsAsync(pdfBytes);
        
        // Option 2: Convert to Base64 using extension method
        string base64Zip = await zipStream.ToBase64StringAsync();
        
        Console.WriteLine($"ZIP as Base64: {base64Zip.Substring(0, 50)}...");
    }

    public async Task ExtractAttachmentsToBytesAsync(Stream pdfStream)
    {
        // Returns ZIP as Stream
        using var zipStream = await _attachmentClient.ExtractAttachmentsAsync(pdfStream);
        
        // Option 3: Convert to byte array using extension method
        byte[] zipBytes = await zipStream.ToBytesAsync();
        
        Console.WriteLine($"ZIP size: {zipBytes.Length} bytes");
    }
}

3. PDF Operations (Merge, Annotate, Stamp)

using DocumentService.Client.Interfaces;
using DocumentService.Client.Models.Requests;
using DocumentService.Client.Models.ValueObjects;
using DocumentService.Client.Extensions; // For Stream extensions

public class OperationsService
{
    private readonly IPdfOperationsClient _operationsClient;

    public OperationsService(IPdfOperationsClient operationsClient)
    {
        _operationsClient = operationsClient;
    }

    // MERGE
    public async Task<Stream> MergePdfsAsync(List<string> pdfPaths)
    {
        var streams = pdfPaths.Select(File.OpenRead).ToList();
        
        // Returns merged PDF as Stream
        var mergedStream = await _operationsClient.MergeAsync(
            streams, 
            pageRanges: new List<string?> { "1-2", null, "3,5" } // Optional
        );
        
        foreach (var stream in streams) stream.Dispose();
        
        return mergedStream; // Caller responsible for disposing
    }

    public async Task MergePdfsToFileAsync(List<string> pdfPaths, string outputPath)
    {
        using var mergedStream = await MergePdfsAsync(pdfPaths);
        
        // Save to file
        using var fileStream = File.Create(outputPath);
        await mergedStream.CopyToAsync(fileStream);
    }

    // ANNOTATE
    public async Task<byte[]> AddHighlightAsync(byte[] pdfBytes)
    {
        var request = new AddAnnotationBase64Request
        {
            Base64Pdf = Convert.ToBase64String(pdfBytes),
            AnnotationType = AnnotationType.TextMarkup,
            PageNumber = 1,
            X1 = 100,
            Y1 = 200,
            Width = 150,
            Height = 20,
            Color = "FFFF00", // Yellow
            TextMarkupStyle = TextMarkupStyle.Highlight,
            Origin = AnnotationOrigin.TopLeft
        };

        // Returns Stream - convert to bytes
        using var annotatedStream = await _operationsClient.AnnotateAsync(pdfBytes, request);
        return await annotatedStream.ToBytesAsync();
    }

    // STAMP
    public async Task<Stream> AddStampAsync(Stream pdfStream)
    {
        var request = new AddStampBase64Request
        {
            Base64Pdf = string.Empty, // Will be filled by client
            StampType = StampType.Text,
            X = 300,
            Y = 50,
            Text = "CONFIDENTIAL",
            FontName = "Arial",
            FontSize = 24,
            Color = "FF0000", // Red
            Opacity = 0.5,
            Rotation = 45,
            Placement = StampPlacement.Foreground,
            Origin = AnnotationOrigin.BottomLeft
        };

        // Returns stamped PDF as Stream
        return await _operationsClient.StampAsync(pdfStream, request);
    }
}

4. Swiss QR Code Extraction

using DocumentService.Client.Interfaces;

public class QrCodeService
{
    private readonly ISwissQrCodeClient _qrCodeClient;

    public QrCodeService(ISwissQrCodeClient qrCodeClient)
    {
        _qrCodeClient = qrCodeClient;
    }

    public async Task ExtractQrCodeAsync(byte[] pdfBytes)
    {
        // Get parsed Bill object
        var result = await _qrCodeClient.ExtractSwissQrCodeAsync(pdfBytes, raw: false);
        
        Console.WriteLine($"Bill: {result.Bill}");
    }

    public async Task ExtractRawQrCodeAsync(Stream pdfStream)
    {
        // Get raw QR text lines
        var result = await _qrCodeClient.ExtractSwissQrCodeAsync(pdfStream, raw: true);
        
        Console.WriteLine("Raw QR Lines:");
        foreach (var line in result.RawLines)
        {
            Console.WriteLine($"  {line}");
        }
    }
}

API Endpoints

Client Method API Endpoint Description
IPdfValidationClient ValidatePdfAsync() POST /api/pdf/validation/validate Validates PDF and returns metadata
IPdfValidationClient ValidatePdfAAsync() POST /api/pdf/validation/validate-pdfa Validates PDF/A conformance
IPdfAttachmentClient CheckAttachmentsAsync() POST /api/pdf/attachments/check Checks for embedded attachments
IPdfAttachmentClient ExtractAttachmentsAsync() POST /api/pdf/attachments/extract Extracts attachments as ZIP
IPdfOperationsClient MergeAsync() POST /api/pdf/operations/merge Merges multiple PDFs
IPdfOperationsClient AnnotateAsync() POST /api/pdf/operations/annotate Adds annotations (highlight, notes, etc.)
IPdfOperationsClient StampAsync() POST /api/pdf/operations/stamp Adds text/image stamps
ISwissQrCodeClient ExtractSwissQrCodeAsync() POST /api/pdf/qr-code/extract-swiss Extracts Swiss QR Code data

Error Handling

try
{
    var result = await validationClient.ValidatePdfAsync(pdfBytes);
}
catch (HttpRequestException ex)
{
    Console.WriteLine($"HTTP error: {ex.Message}");
}
catch (InvalidOperationException ex)
{
    Console.WriteLine($"API returned null: {ex.Message}");
}

License

Copyright © 2026 Digital Data GmbH. All rights reserved.