【问题标题】:C# is crashing on an eventC# 在一个事件上崩溃
【发布时间】:2020-05-10 06:36:11
【问题描述】:

我正在尝试将 C# 服务创建为控制台应用程序。

主要代码:

static void Main(string[] args)
{
        var exitCode = HostFactory.Run(
            x =>
            {
                x.Service<HeartBeat>(s =>
                {
                    s.ConstructUsing(heartbeat => new HeartBeat());
                    s.WhenStarted(heartbeat => heartbeat.Start());
                    s.WhenStopped(heartbeat => heartbeat.Stop());
                });

                x.RunAsLocalSystem();
                x.SetServiceName("UpgradeServices");
                x.SetDisplayName("Service Upgrade");
                x.SetDescription("Service is monitoring new version.");
            });

        int exitCodeValue = (int)Convert.ChangeType(exitCode, exitCode.GetTypeCode());
        Environment.ExitCode = exitCodeValue;
}

然后我有删除和复制文件的代码,如下所示:

public class MovingFiles
{
    public string fileName;
    public string destPath;
    private DirectoryInfo directory;
    private DirectoryInfo myFile;
    public string sourcePath;
    public string targetPath;

    public MovingFiles(string sourceFolder, string targetFolder)
    {
        sourcePath = sourceFolder;
        targetPath = targetFolder;
    }

    public void deleteFilesMethod()
    {
        System.Threading.Thread.Sleep(10000);
        string deleteString;
        //First we want to delete all files except for the JSON file as this has all of the important settings
        if (System.IO.Directory.Exists(targetPath))
        {
            string[] files = System.IO.Directory.GetFiles(targetPath);

            // Loop through each files and then delete these if they are not the JSON file
            foreach (string s in files)
            {
                deleteString = targetPath;
                // The file name which is returned will be deleted
                fileName = System.IO.Path.GetFileName(s);

                if (fileName != "appsettings.json")
                {
                    deleteString = System.IO.Path.Combine(targetPath, fileName);

                    try
                    {
                        System.IO.File.Delete(deleteString);
                    }
                    catch (System.IO.IOException e)
                    {
                        Console.WriteLine(e.Message);
                        return;
                    }
                }
            }
        }
        else
        {
            Console.WriteLine("The loop didn't run, source path doesn't exist");
        }
    }

    public void copyFilesMethod()
    {
        System.Threading.Thread.Sleep(10000);

        if (System.IO.Directory.Exists(sourcePath))
        {
            // Searching for the latest directory created in the sourcePath folder
            directory = new DirectoryInfo(sourcePath);
            myFile = (from f in directory.GetDirectories()
                      orderby f.LastWriteTime descending
                      select f).First();

            sourcePath = System.IO.Path.Combine(sourcePath, myFile.Name);
            string[] files = System.IO.Directory.GetFiles(sourcePath);

            // Copy the files and overwrite destination files if they already exist.
            foreach (string s in files)
            {
                // Use static Path methods to extract only the file name from the path.
                fileName = System.IO.Path.GetFileName(s);

                if (fileName != "appsettings.json")
                {

                    destPath = System.IO.Path.Combine(targetPath, fileName);

                    try
                    {
                        System.IO.File.Copy(s, destPath, true);
                    }
                    catch (System.IO.IOException e)
                    {
                        Console.WriteLine(e.Message);
                        return;
                    }
                }
            }
        }
        else
        {
            Console.WriteLine("The loop didn't run, source path doesn't exist");
        }

        // Keep console window open in debug mode.
        Console.WriteLine("Procedure has been completed.");
}

一旦有一个新文件就应该触发这个,我写成这样:

class FileMonitor
{
    public FileSystemWatcher watcher = new FileSystemWatcher();
    public string sourcePath;
    public string targetPath;

    public FileMonitor(string sourceFolder, string targetFolder)
    {
        sourcePath = sourceFolder;
        targetPath = targetFolder;
    }

    public void watch()
    {
            watcher.Path = sourcePath;
            watcher.NotifyFilter =  NotifyFilters.LastWrite
                                   | NotifyFilters.FileName | NotifyFilters.DirectoryName
                                   | NotifyFilters.CreationTime;
            //var one = NotifyFilters.FileName;
            watcher.Filter = "*.*";
            watcher.Created += new FileSystemEventHandler (OnChanged);
            watcher.EnableRaisingEvents = true;
            //System.Threading.Thread.Sleep(25000);
    }

    public void OnChanged(object source, FileSystemEventArgs e)
    {
        //Copies file to another directory.
        MovingFiles FileMoveOne = new MovingFiles(sourcePath, targetPath);
        FileMoveOne.deleteFilesMethod();
        FileMoveOne.copyFilesMethod();

    }
}

我的理解是,一旦我运行下面的内容,如果有一个新文件然后触发 OnChange 方法,它会每 10 秒查看一次,对吗?

public class HeartBeat
{
    private readonly Timer _timer;

    public HeartBeat()
    {
        _timer = new Timer(10000)
        {
            AutoReset = true
        };
        _timer.Elapsed += TimerElapsed;
    }

    private void TimerElapsed(object sender, ElapsedEventArgs e)
    {
        //StringBuilder loggingLine = new StringBuilder();
        /* Every 30 seconds it will write to the file */
        string[] lines = new string[] {DateTime.Now.ToString() + ": Heartbeat is active. Service is monitoring SS and DS"};
        //lines[1] = DateTime.Now.ToString() + " About to check if new files are placed on server";

            //loggingLine.Append(lines[i]);
            File.AppendAllLines(@"C:\Users\RLEBEDEVS\Desktop\Monitor\Monitor1\HeartBeat.log", lines);
        //File.AppendAllLines(@"C:\Users\RLEBEDEVS\Desktop\Monitor\Monitor1\HeartBeat.log", lines);
        FileMonitor versioOne = new FileMonitor(@"C:\Users\RLEBEDEVS\Desktop\Monitor\Monitor1", @"C:\Users\RLEBEDEVS\Desktop\Monitor\Monitor2");
        versioOne.watch();
    }

    public void Start ()
    {
        _timer.Start();
    }

    public void Stop ()
    {
        _timer.Stop();
    }
}

我遇到的问题是不一致。

  1. 创建新文件夹后,它应该将文件复制到文件夹 Monitor2,但在第一次创建时不会这样做。一旦在monitor1文件夹中创建文件夹,它会第二次删除并复制文件。

  2. 每第二次尝试复制文件时,它都会因以下我不熟悉的错误而崩溃:

    Topshelf.Hosts.ConsoleRunHost 严重:0:服务抛出未处理的异常,System.UnauthorizedAccessException:访问路径“C:\Users\RLEBEDEVS\Desktop\Monitor\Monitor2\System.Net.Sockets.dll”是拒绝。
    在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    在 System.IO.File.InternalDelete(字符串路径,布尔检查主机)
    在 System.IO.File.Delete(字符串路径)
    在 C:\Users\RLEBEDEVS\Desktop\C#\Service\UpgradeServices\MovingFIles.cs:line 48 中的 UpgradeServices.MovingFiles.deleteFilesMethod()
    在 C:\Users\RLEBEDEVS\Desktop\C#\Service\UpgradeServices\FileMonitor.cs:line 43 中的 UpgradeServices.FileMonitor.OnChanged(Object source, FileSystemEventArgs e)
    在 System.IO.FileSystemWatcher.OnCreated(FileSystemEventArgs e)
    在 System.IO.FileSystemWatcher.NotifyFileSystemEventArgs(Int32 操作,字符串名称)
    在 System.IO.FileSystemWatcher.CompletionStatusChanged(UInt32 错误代码,UInt32 numBytes,NativeOverlapped* 重叠指针)
    在 System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

    Topshelf.Hosts.ConsoleRunHost 信息:0:停止 UpgradeServices 服务
    Topshelf.Hosts.ConsoleRunHost 信息:0:UpgradeServices 服务已停止。

    程序“[497452] UpgradeServices.exe”已退出,代码为 1067 (0x42b)。

第 48 行就是这一行,尽管它执行了之前很好的任务(在第一次运行时)。

System.IO.File.Delete(deleteString);

我发现问题在于我提出事件的方式。有谁知道我应该改变什么才能达到预期的结果,即在命运中创建的每个新文件夹上启动服务时,它将执行移动和删除文件的两种方法?该文件夹将始终只创建新文件夹。

问候,

【问题讨论】:

  • 您的程序是否试图删除System.Net.Sockets.dll?它应该这样做吗?
  • 您是否尝试通过首先删除可执行文件目录中的文件来更新您自己的服务?那是行不通的。您不能删除或覆盖应用程序当前正在执行的文件。有不同的方法可以做到这一点,但不能通过正在更新的应用程序本身来完成。
  • 删除文件夹的文件不是服务所在的位置。那里的文件用于不同的服务。

标签: c# events filesystemwatcher


【解决方案1】:

在您的心跳中,您似乎每 10 秒开始新的FileMonitor,因此 20 秒后您将有 2 个FileMonitor 同时观看和移动(删除)相同的文件。例如,使用hosted service 启动一次FileMonitor。或者删除 HeartBeat 类中的计时器处理程序部分,然后在构造函数中创建 FileMonitor

public HeartBeat()
{
    FileMonitor versioOne = new 
    FileMonitor(@"C:\Users\RLEBEDEVS\Desktop\Monitor\Monitor1", @"C:\Users\RLEBEDEVS\Desktop\Monitor\Monitor2");
    versioOne.watch(); 
   // may be save it to instance field so it does not get garbage collected.
   // Not sure how FileSystemWatcher behaves with subscription, 
   // it should prevent the "versionOne" from being collected via subscription.
}

【讨论】:

  • 这实际上看起来工作得很好。两个问题。我需要计时器才能让它监控文件夹吗?我将在第一个上做一些额外的测试,一旦我将 FileMonitor 和 versionOne.watch 移动到 constrictor,它确实工作并且没有崩溃。
  • @RaitisLebedevs,不,你不这样做,FileSystemWatcher 不断监听指定目录中的更改,直到它被释放。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多