【问题标题】:C# based Windows Service starts and then stops - why?基于 C# 的 Windows 服务启动然后停止 - 为什么?
【发布时间】:2010-10-21 04:07:47
【问题描述】:

我已经构建了一个 Windows 服务,但由于某种原因,当我启动该服务时,它会启动,然后又立即关闭。我试过用谷歌搜索为什么会这样。任何系统日志中都没有出现任何内容。这是我的服务的启动/停止代码。我希望因为我创建了一个文件侦听器,它应该保持运行。我错过了什么?

#region Declarations
private List<string> _keys = new List<string>();
private FileSystemWatcher _watcher;
private BackgroundWorker _worker;
static private bool _isBusy = false;
#endregion

#region Constructor
public FeedListener()
{
    InitializeComponent();
}
#endregion

#region Start/Stop
protected override void OnStart(string[] args)
{
    _keys.AddRange(new string[] { "csv", "xml", "zip", "rivx" });

    _worker = new BackgroundWorker();
    _worker.WorkerReportsProgress = true;
    _worker.WorkerSupportsCancellation = true;
    _worker.DoWork += new DoWorkEventHandler(BackgroundWorkerDoWork);
    _worker.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorkerProgressChanged);
    _worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerRunWorkerCompleted);

    _watcher = new FileSystemWatcher(AppSettings.Default.FTPRootPath, "*.*");
    _watcher.IncludeSubdirectories = true;
    _watcher.NotifyFilter = sysIO.NotifyFilters.DirectoryName | sysIO.NotifyFilters.FileName | sysIO.NotifyFilters.LastAccess | sysIO.NotifyFilters.CreationTime | sysIO.NotifyFilters.LastWrite;
    _watcher.Created += new sysIO.FileSystemEventHandler(fileCreatedOrChanged);
    _watcher.Changed += new sysIO.FileSystemEventHandler(fileCreatedOrChanged);
    _watcher.EnableRaisingEvents = true;

    TouchFiles();
}
protected override void OnStop()
{
    _watcher.Dispose();
    _watcher = null;
    _worker.Dispose();
    _worker = null;
}
#endregion

#region Event Handlers
void fileCreatedOrChanged(object sender, sysIO.FileSystemEventArgs e)
{
    DTO.BackgroundWorkerEventArgs eventArgs = new DTO.BackgroundWorkerEventArgs();
    sysIO.WatcherChangeTypes myType = e.ChangeType;

    bool isValid = false;
    foreach (string key in _keys)
    {
        if (Path.GetExtension(e.FullPath).Replace(".", "").Equals(key, StringComparison.CurrentCultureIgnoreCase))
            isValid = true;
    }
    if (isValid)
    {
        try
        {
            eventArgs.PathAndFile = e.FullPath;
            eventArgs.Key = Path.GetExtension(e.FullPath).ToLower().Replace(".", "");
            eventArgs.FileName = Path.GetFileName(e.FullPath);
            eventArgs.Path = Path.GetDirectoryName(e.FullPath);
            eventArgs.UserName = Path.GetDirectoryName(e.FullPath).Replace(AppSettings.Default.FTPRootPath, "").Replace("\\", "");

            FileInfo fileInfo = new FileInfo(eventArgs.PathAndFile);

            // 1st attempt at stalling for the file lock due to slow write speeds...
            while (IsFileLocked(fileInfo)) { /* nop */ }

            // Wait until the thread is not busy...
            //while (_worker.IsBusy) { /* nop */ }
            while (_isBusy) { /* nop */ }

            // Now, spin up a new thread and do the work on the file, based on file type...
            _worker.RunWorkerAsync(eventArgs);  // goes to BackgroundWorkerDoWork(object sender, DoWorkEventArgs e) //
        }
        catch (Exception ex)
        {
            string m = ex.Message;
        }
    }
}
void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
    DTO.BackgroundWorkerEventArgs eventArgs = (DTO.BackgroundWorkerEventArgs)e.Argument;
    RivWorks.FeedHandler.Handler handler = new RivWorks.FeedHandler.Handler();
    _isBusy = true;

    try
    {
        if (eventArgs.Key.Equals("csv", StringComparison.CurrentCultureIgnoreCase))
        {
            handler.ImportCSV(ref eventArgs);
        }
        if (eventArgs.Key.Equals("zip", StringComparison.CurrentCultureIgnoreCase))
        {
            handler.UnZip(ref eventArgs);
            handler.ImportCSV(ref eventArgs);
        }
    }
    catch (Exception ex)
    {
        string m = ex.Message;
        _worker.ReportProgress(0);
    }
    finally
    {
        _isBusy = false;
        _worker.ReportProgress(100);
        if (_worker.CancellationPending)
        {
            e.Cancel = true;
        }
    }
}
void BackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        Console.WriteLine("Cancelled.");
    }
    else if (e.Error != null)
    {
        Console.WriteLine(e.Error.Message);
    }
    else
    {
        Console.WriteLine("Successfully completed.");
    }

    TouchFiles();
}
#endregion

【问题讨论】:

  • 当 FileListener 对象运行时,服务正在“工作”。它正在侦听文件。 :) 我添加了一个 try/catch 并将所有错误写到事件日志中。我发现我的一个路径(在 app.config 中)被设置为 UNC 而不是驱动器号。改变了这一点,瞧,它启动并做了它应该做的事情。上面的答案不是这种情况的正确答案。亚当的评论是最正确的。 (现在,答案似乎被删除了!)

标签: c# windows-services


【解决方案1】:

我没有看到 TouchFiles() 的代码,但这听起来像是问题的根源。就像它迭代磁盘驱动器上的所有目录一样。这需要很长时间,比服务控制管理器愿意忍受的服务启动时间还要长(我认为是 30 秒)。

启动一个线程并让它接触文件。还要注意您的 BackgroundWorker,这些事件不会在启动它的同一线程上调用。这需要一个服务中不可用的同步提供程序。

【讨论】:

  • 一个小提示:您可以使用 ServiceBase.RequestAdditionalTime 让 SCM 等待更长的时间,但这是一个非常糟糕的主意。
  • TouchFiles - 循环 _keys 列表提供的扩展并将 LastModifiedTime 设置为现在。我正在收听的目录是提要文件的 FTP 放置目录。启动时,可能有一两个文件仍在等待处理。所以,我“触摸”文件来触发 FileListener。如果每个文件都在那里,则此方法需要
  • 好吧,那不太可能。为您的代码添加一些日志记录、显示时间戳、注意异常。
  • 我认为这是一个例外,就像你说的那样,这会导致崩溃。根据他的另一篇文章,TouchFiles() 正在更新目录中所有文件的文件时间,这会多次触发 fileCreatedOrChanged 事件,这会在同一个 BackgroundWorker 上多次调用 RunWorkerAsync()。请参阅下面的答案
  • 这就是我从不使用这些东西的原因 ;) ...jk
【解决方案2】:

为什么不直接调试呢?在OnStart方法中添加Debugger.Break()

【讨论】:

  • 这行不通。在您有时间做任何事情之前,SCM 会检测到缺乏响应并终止您的进程。
  • 我做了很多。正如史蒂夫所说——作为一项服务,它几乎是不可能调试的。
  • 先制作一个控制台Exe。运行它以确保您的逻辑是正确的。 然后将其转换为作为服务运行。这就是我过去调试类似情况的方式。
  • @Steve Townsend:以前从未遇到过问题。也许我有那个错误的位置。 @Keith Barrows 尝试在“DoWork”中添加对Break 的调用。这将允许 OnStart 完成并且不会导致“超时”。
  • 我确实有一个 EXE (TestHarness),我在 Dev 中运行它。那里一切正常。我现在正在剥离大部分内容并将所有工作推入 BackgroundWorker 线程......
【解决方案3】:

我在您的其他相关帖子中发布了答案...我认为问题在于您在同一个 BackgroundWorker 上触发了多个 RunWorkAsync 调用,这可能会导致服务崩溃。

另外,您在多线程后台工作人员的上下文中使用 _isBusy 标志...您需要使用多线程锁定系统,例如 Mutex(尽管我仍然说这会破坏运行点BackgroundWorkers 异步)。

在这里查看答案:C# based Windows Service - Tries to do JIT Debugging in production

【讨论】:

  • 我的异步调用确实有点侧向。回到白板上,把主要组件流出来,重新编写我的代码。感谢大家。几个很好的指针,但这是最接近的。
【解决方案4】:

也许您需要在 OnStart 的某个地方调用 base.OnStart?

【讨论】:

    【解决方案5】:

    我不知道TouchFiles 是做什么的,但是Windows 服务通常在loop eq 中运行。 while(true),你的似乎没有。

    【讨论】:

      【解决方案6】:

      尝试在 OnStart 方法的开头添加 Debugger.Launch() 行并逐步执行,直到遇到导致问题的任何异常。

      另一方面,我会重构设计,以便将大部分工作放在一个单独的可测试类中,并且只需连接服务中的最低限度。

      【讨论】:

        【解决方案7】:

        看起来您的 OnStart 只是简单地执行和退出,您并没有让应用程序保持活动状态,它就像一个控制台应用程序,开始运行然后退出。如果是这种情况,您需要等待诸如结束/关闭服务事件之类的事情,并让您的工作后台线程处理传入的工作请求,并且在您的应用程序收到终止信号之前不要退出此例程,也许来自一个事件。

        【讨论】:

          【解决方案8】:

          您确定您使用的是为您生成的正确服务启动代码吗?如果它只是作为应用程序运行,则可能会发生这种情况。当我有一个单独的用于测试的 Main() 时,就会发生这种情况。

          【讨论】:

            猜你喜欢
            • 2011-11-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多