C# based Windows Service starts and then stops - why?
I have built a Windows Service and for some reason, when I start the service it starts up and then shuts right back down. I’ve tried googling why this is happening. Nothing is appearing in any system logs. Here is my Start/Stop code for the service. I would expect that since I have created a File Listener that it should stay running. What am I missing?
#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.C开发者_StackOverflowurrentCultureIgnoreCase))
{
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
I don't see the code for TouchFiles() but it sounds like the source of the problem. Like when it iterates all of the directories on a disk drive. That takes a lot of time, longer then the Service Control Manager is willing to put up with for a service to get started (30 seconds, I think).
Start a thread and have it touch the files. Also beware of your BackgroundWorker, the events are not called on the same thread that started it. That takes a synchronization provider that is not available in a service.
Why dont you just debug it? Add Debugger.Break()
in the OnStart
method.
I posted an answer in your other, related post... I believe the issue is that you're firing multiple RunWorkAsync
calls on the same BackgroundWorker, and this is probably crashing the service.
Also, you're using an _isBusy flag in the context of multi-threaded background workers... you need to use a multi-threaded locking system, such as a Mutex (though I still say that defeats the point of running BackgroundWorkers asynchronously).
Check the answer here: C# based Windows Service - Tries to do JIT Debugging in production
Maybe you need to call base.OnStart somewhere in OnStart?
I don't know what TouchFiles
does, but a windows service normally runs in loop eq. while(true)
, which yours does not seem to do.
Try adding a Debugger.Launch()
line at the beginning of your OnStart method and step through until you encounter whatever exception is causing the problem.
On another note, I'd refactor the design so the bulk of the work is in a separate and testable class, and just wire up the bare minimum in the service.
It looks like your OnStart simply executes and exits, you're not keeping the application alive, it's acting like a console app, start run through and then exit. If this is the case, you need to wait for something like an end/shutdown service event, and let your worker background thread process the incoming work requests and not exit this routine until your app gets signaled to terminate, from an event perhaps.
Are you sure you are using the correct service startup code that is generated for you? This could happen if it is just running as an app. I've had this happen when I have a separate Main() I use for testing.
精彩评论