Search code examples
c#linuxdocker.net-corefilesystemwatcher

Why FileSystemWatcher doesn't work in Linux container watching Windows volume


Given the program:

using System;
using System.IO;

namespace fsw_bug_poc
{
    class Program
    {
        private static FileSystemWatcher _fileSystemWatcher;

        static void Main(string[] args)
        {
            _fileSystemWatcher = new FileSystemWatcher("Watched", "*.*");
            _fileSystemWatcher.Changed += Notify;
            _fileSystemWatcher.Created += Notify;
            _fileSystemWatcher.Deleted += Notify;
            _fileSystemWatcher.Renamed += Notify;
            _fileSystemWatcher.IncludeSubdirectories = true;
            _fileSystemWatcher.EnableRaisingEvents = true;

            Console.ReadKey(false);
        }

        private static void Notify(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine($"{e.FullPath} {e.ChangeType}");
        }
    }
}

The Dockerfile:

FROM mcr.microsoft.com/dotnet/core/runtime:2.2-stretch-slim AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["fsw-bug-poc.csproj", ""]
RUN dotnet restore "fsw-bug-poc.csproj"
COPY . .
WORKDIR "/src/"
RUN dotnet build "fsw-bug-poc.csproj" -c Release -o /app

FROM build AS publish
RUN dotnet publish "fsw-bug-poc.csproj" -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENV DOTNET_USE_POLLING_FILE_WATCHER=true
RUN mkdir -p /app/Watched
VOLUME /app/Watched
ENTRYPOINT ["dotnet", "fsw-bug-poc.dll"]

According to this link adding ENV DOTNET_USE_POLLING_FILE_WATCHER=true to the Dockerfile fixes the FileSystemWatcher not working inside the container.

Even with this fix, FileSystemWatcher will not work when running a Linux container on Windows and mounting a shared driver to a volume:

docker build -t fsw-bug-poc .
docker run -it --rm -v C:\Shared:/app/Watched fsw-bug-poc

Modifying a file inside the container:

running touch inside the container

touch working inside container

Modifying files in the shared volume folder:

modifying files in the shared folder

Nothing happens!!

nothing happens when modifying shared folder on windows

Can someone explain what is going on? The FileSystemWatcher is using a polling strategy, so it should work the same way, shouldn't it?


Solution

  • Switching to PhysicalFileProvider did the job.
    It seems to be a more portable implementation for file system watching strategies.

    The current implementation of PhysicalFileProvider supports the DOTNET_USE_POLLING_FILE_WATCHER environment variable. I couldn't find any reference of it in FileSystemWatcher implementation.

    using Microsoft.Extensions.FileProviders;
    using Microsoft.Extensions.Primitives;
    using System;
    using System.IO;
    
    namespace fsw_bug_poc
    {
        class Program
        {
            private static PhysicalFileProvider _fileProvider;
            private static IChangeToken _fileChangeToken;
    
            static void Main(string[] args)
            {
                _fileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "."));
                WatchForFileChanges();
    
                Console.ReadKey(false);
            }
    
            private static void WatchForFileChanges()
            {
                _fileChangeToken = _fileProvider.Watch("*.*");
                _fileChangeToken.RegisterChangeCallback(Notify, default);
            }
    
            private static void Notify(object state)
            {
                Console.WriteLine("File change detected");
                WatchForFileChanges();
            }
        }
    }