我有一个Windows服务,它只是默默地自行停止。 以下是相关代码:
OnStart() 方法:
protected override void OnStart(string[] args)
{
try
{
InitializeLogging();
// we don't DO command line arguments
if (args.Length > 0)
{
eventLog.WriteEntry("All command line arguments are ignored. You must edit the app.config file manually to make changes to what watchers are run.");
throw new ArgumentException("Command line arguments are ignored.");
}
ReadAppConfig();
RecalculateStartTimes();
InitializeWatchers();
}
catch (Exception e)
{
eventLog.WriteFormattedEntry("Error on Start: {0}", e.Message);
}
finally
{
eventLog.WriteEntry("Service start completed");
}
}
OnStop() 方法:
protected override void OnStop()
{
eventLog.WriteEntry("Service stopped.");
}
InitializeWatchers() 方法:
private void InitializeWatchers()
{
try
{
var watchers = _watcherSection.Watchers.ToList<WatcherElement>();
eventLog.WriteEntry(string.Format("Initializing {0} watchers.", watchers.Count()));
var obsWatchers = watchers.ToObservable();
obsWatchers.SelectMany(
watcher =>
Observable.Timer(watcher.StartTime, TimeSpan.FromHours(watcher.Interval))
.SelectMany(
Observable.FromAsync(
async () => new
{
watcher,
response = await CheckFolder(watcher.Path)
})))
.Subscribe(
onNext: x =>
{
eventLog.WriteFormattedEntry("nWatcher: {0}, Time:{1}", x.watcher.Name, DateTimeOffset.Now);
if (x.response.Success)
eventLog.WriteFormattedEntry("| Success!n| Value: '{0}'n| Message: {0}", x.response.Value, x.response.Message);
else
eventLog.WriteFormattedEntry("| FAILURE!n| Value: '{0}'n| Message: {0}n| Errors: '{0}'", x.response.Value, x.response.Message, x.response.Exceptions.First());
},
onError: e =>
{
var err = e;
var sb = new StringBuilder();
sb.AppendLine("The observer threw an error:")
.AppendFormatLine("| Message: {0}", e.Message);
while (e.InnerException != null)
{
sb.AppendFormatLine("| Inner: {0}", e.InnerException.Message);
e = e.InnerException;
}
sb.AppendLine();
eventLog.WriteEntry(sb.ToString());
throw err;
});
eventLog.WriteEntry("about to wait.");
obsWatchers.Wait();
eventLog.WriteEntry("passed the wait");
}
catch (Exception e)
{
eventLog.WriteFormattedEntry("Exception thrown in InitializeWatchers(WatchersSection): {0}", e.Message);
throw;
}
}
当我运行此代码时,服务正常启动。 事件日志记录三个事件:
- 服务和日志记录开始。
- 初始化 1 个观察程序。
- 服务启动完成。
。然后它停止了。 我必须手动刷新"服务"窗口,但它停止运行。 我没有收到任何错误或任何其他事件日志条目。
令人沮丧的是,此代码可以完美地用作控制台应用程序。 我已经将所有 eventLog.WriteEntry() 更改为 Console.WriteLine(),但除此之外,代码是相同的,并且按预期执行。
任何智慧都将不胜感激。
我怀疑服务控制管理器正在终止您的服务,因为它没有在超时窗口(30 秒,IIRC)内从OnStart
返回。
我有一篇关于托管服务基础知识的博客文章,该文章基于 BCL 团队的博客文章。请注意,MSDN 文档是不够的;必须了解 BCL 团队博客文章中的信息才能正确编写托管服务。
与其使用阻止并导致斯蒂芬所说的问题的obsWatchers.Wait()
,不如异步订阅。
将此属性添加到类中:
private SingleAssignmentDisposable _subscription = new SingleAssignmentDisposable();
将此添加到您的OnStop
方法中:
_subscription.Dispose();
在 InitializeWatchers()
中,消除嵌套的Subscribe
调用,并将obsWatchers.Wait()
替换为订阅调用,如下所示:
private void InitializeWatchers()
{
try
{
var watchers = _watcherSection.Watchers.ToList<WatcherElement>();
eventLog.WriteEntry(string.Format("Initializing {0} watchers.", watchers.Count()));
var obsWatchers = watchers.ToObservable();
_subscription.Disposable = obsWatchers
.SelectMany(watcher => Observable
.Timer(watcher.StartTime, TimeSpan.FromHours(watcher.Interval))
.SelectMany(_ => Observable.FromAsync(async () => new
{
watcher,
response = await CheckFolder(watcher.Path)
})))
.Subscribe(
onNext: x =>
{
eventLog.WriteFormattedEntry("nWatcher: {0}, Time:{1}", x.watcher.Name, DateTimeOffset.Now);
if (x.response.Success)
eventLog.WriteFormattedEntry("| Success!n| Value: '{0}'n| Message: {0}", x.response.Value, x.response.Message);
else
eventLog.WriteFormattedEntry("| FAILURE!n| Value: '{0}'n| Message: {0}n| Errors: '{0}'", x.response.Value, x.response.Message, x.response.Exceptions.First());
},
onError: e =>
{
var err = e;
var sb = new StringBuilder();
sb.AppendLine("The observer threw an error:")
.AppendFormatLine("| Message: {0}", e.Message);
while (e.InnerException != null)
{
sb.AppendFormatLine("| Inner: {0}", e.InnerException.Message);
e = e.InnerException;
}
sb.AppendLine();
eventLog.WriteEntry(sb.ToString());
throw err;
});
eventLog.WriteEntry("passed the wait");
}
catch (Exception e)
{
eventLog.WriteFormattedEntry("Exception thrown in InitializeWatchers(WatchersSection): {0}", e.Message);
throw;
}
}