23

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?

natenho
  • 5,231
  • 4
  • 27
  • 52
  • 1
    In the past, Windows file notifications only worked on Windows machines. They did not work using SMB shares on AIX, Linux or OS/400 I was working on at the time. I used to have to poll the shares for changes. – jww Jul 14 '19 at 05:06
  • 1
    I am not sure if that will affect the FileSystemWatcher strategy - read https://learn.microsoft.com/dotnet/api/microsoft.extensions.fileproviders.physicalfileprovider?view=aspnetcore-2.2 => *UsePollingFileWatcher* – Sir Rufo Jul 14 '19 at 05:15
  • @SirRufo you're probably right. I thought FileSystemWatcher was using it under the hoods, but it seems that is the opposite: https://github.com/aspnet/FileSystem/blob/master/src/FS.Physical/PhysicalFileProvider.cs – natenho Jul 14 '19 at 06:01

1 Answers1

18

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();
        }
    }
}
Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
natenho
  • 5,231
  • 4
  • 27
  • 52