From Theory to Practice: Building a File Watcher Service

From Theory to Practice: Building a File Watcher Service

After understanding the fundamentals of Worker Services, let's explore a practical implementation: a File Watcher Service. This real-world example demonstrates how to apply the concepts we've learned to create a robust, production-ready service.

The Challenge

Imagine you need to monitor a directory for new files, perhaps for processing financial transactions or handling automated data imports. You need a service that:

  • Runs continuously
  • Monitors a specific directory
  • Processes new files as they arrive
  • Maintains security and stability
  • Restarts automatically if it fails

The Solution

Let's create a File Watcher Service that fulfills these requirements. We'll build upon our Worker Service knowledge and add file system monitoring capabilities.

Step 1: Basic Structure

First, let's set up our Worker class with file watching capabilities:

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;
    private FileSystemWatcher? _watcher;
    private readonly string _watchPath;
    private readonly string _fileFilter;

    public Worker(ILogger<Worker> logger, IConfiguration configuration)
    {
        _logger = logger;
        // Get watch path from configuration
        _watchPath = configuration.GetValue<string>("WatchSettings:FolderPath")
            ?? throw new ArgumentNullException("WatchSettings:FolderPath must be set");
        _fileFilter = configuration.GetValue<string>("WatchSettings:FileFilter") ?? "*.txt";
    }
}

Step 2: Configuration

In appsettings.json, we define our watching parameters:

{
  "WatchSettings": {
    "FolderPath": "C:\\WatchFolder",
    "FileFilter": "*.txt"
  }
}

Step 3: Implementing the File Watcher

Now, let's implement the file watching logic:

public override Task StartAsync(CancellationToken cancellationToken)
{
    _logger.LogInformation("Worker starting at: {time}", DateTimeOffset.Now);
    
    // Ensure directory exists
    if (!Directory.Exists(_watchPath))
    {
        Directory.CreateDirectory(_watchPath);
        _logger.LogInformation("Created watch directory: {path}", _watchPath);
    }

    // Initialize FileSystemWatcher
    _watcher = new FileSystemWatcher
    {
        Path = _watchPath,
        Filter = _fileFilter,
        NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite,
        EnableRaisingEvents = true
    };

    // Hook up events
    _watcher.Created += OnFileCreated;
    _watcher.Error += OnError;

    return base.StartAsync(cancellationToken);
}

Step 4: File Processing Logic

Here's how we handle new files:

private void OnFileCreated(object sender, FileSystemEventArgs e)
{
    try
    {
        _logger.LogInformation("New file detected: {file}", e.Name);
        
        // Wait briefly to ensure file is completely written
        Thread.Sleep(100);

        // Process the file
        ProcessFile(e.FullPath);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Error processing file: {file}", e.Name);
    }
}

Step 5: Service Installation

To install as a Windows Service:

# Create the service
sc.exe create "TSVAutomation" binpath= "C:\path\to\service.exe" start= auto

# Configure automatic restart
sc.exe failure "TSVAutomation" reset= 86400 actions= restart/60000/restart/60000/restart/60000

Applying Best Practices

Our implementation incorporates several best practices:

  1. Configuration Management

    • External configuration in appsettings.json
    • Environment-specific settings support
    • Fail-fast when required settings are missing
  2. Error Handling

    • Graceful handling of file system errors
    • Logging of all important events
    • Proper exception management
  3. Resource Management

    • Proper disposal of FileSystemWatcher
    • Clean shutdown handling
    • Memory-conscious file processing
  4. Reliability

    • Automatic service restart
    • File lock prevention
    • Robust error recovery

Real-World Considerations

When implementing this service in production, consider:

  1. Security

    • Proper file access permissions
    • Secure processing of sensitive data
    • Audit logging for file operations
  2. Performance

    • Batch processing for multiple files
    • Resource throttling
    • Monitoring file processing times
  3. Maintenance

    • Log rotation
    • Performance monitoring
    • Health checks

Connecting the Dots

This implementation demonstrates key Worker Service concepts:

  • Background processing
  • Resource management
  • Error handling
  • Configuration
  • Logging
  • Service lifetime management

The File Watcher Service shows how Worker Services can solve real-world problems by:

  • Providing continuous monitoring
  • Handling system events
  • Processing data reliably
  • Managing resources efficiently

Next Steps

To enhance this service, consider:

  1. Adding file archiving
  2. Implementing retry logic
  3. Adding email notifications
  4. Creating a monitoring dashboard
  5. Implementing health checks

Conclusion

By building this File Watcher Service, we've seen how Worker Service concepts translate into practical solutions. This implementation provides a foundation that you can build upon for your specific needs, whether it's processing financial data, handling system automation, or managing file-based workflows.

Remember: The key to a successful Worker Service is balancing functionality with reliability, security, and maintainability.


Have questions about implementing your own Worker Service? Check our previous guide on Worker Service fundamentals!

Understanding Modern .NET Worker Services

Understanding Modern .NET Worker Services