Both solutions can run the program when user isn't logged in, so no difference there. Writing a service is somewhat more involved than a regular desktop app, though - you may need a separate GUI client that will communicate with the service app via TCP/IP, named pipes, etc.
我真的不喜欢 Windows 调度程序。用户的密码必须提供 @ moodforall指出以上,这是有趣的,当有人改变该用户的密码。
Windows 调度程序的另一个主要烦恼是它是交互式运行的,而不是作为后台进程。在 RDP 会话期间,每隔20分钟就会弹出15个 MS-DOS 窗口,如果你没有把它们作为 Windows 服务安装的话,你会后悔的。
无论您选择什么,我当然建议您将处理代码从控制台应用程序或 Windows 服务中分离到不同的组件中。然后,你可以选择从一个控制台应用调用 worker 进程并将其连接到 Windows 计划程序,或者使用 Windows 服务。
您会发现安排 Windows 服务并不有趣。一个相当常见的场景是,您有一个需要定期运行的长时间运行的流程。但是,如果您正在处理一个队列,那么您实际上不希望同一个工作线程的两个实例处理同一个队列。因此,需要管理计时器,以确保长时间运行的进程运行的时间是否超过分配的计时器间隔,在现有进程完成之前,它不会再次启动。
protected override void OnStart (string args) {
// Create worker thread; this will invoke the WorkerFunction
// when we start it.
// Since we use a separate worker thread, the main service
// thread will return quickly, telling Windows that service has started
ThreadStart st = new ThreadStart(WorkerFunction);
workerThread = new Thread(st);
// set flag to indicate worker thread is active
serviceStarted = true;
// start the thread
workerThread.Start();
}
代码实例化一个单独的线程并连接我们的 worker
然后它启动线程并让 OnStart 事件
完成,这样 Windows 就不会认为服务是挂起的。
Worker method for the single-thread approach.
/// <summary>
/// This function will do all the work
/// Once it is done with its tasks, it will be suspended for some time;
/// it will continue to repeat this until the service is stopped
/// </summary>
private void WorkerFunction() {
// start an endless loop; loop will abort only when "serviceStarted"
// flag = false
while (serviceStarted) {
// do something
// exception handling omitted here for simplicity
EventLog.WriteEntry("Service working",
System.Diagnostics.EventLogEntryType.Information);
// yield
if (serviceStarted) {
Thread.Sleep(new TimeSpan(0, interval, 0));
}
}
// time to end the thread
Thread.CurrentThread.Abort();
}
单线程方法的 OnStop 方法。
protected override void OnStop() {
// flag to tell the worker process to stop
serviceStarted = false;
// give it a little time to finish any pending work
workerThread.Join(new TimeSpan(0,2,0));
}
I've been running lots of Windows Services like this for years and it works for me. I still haven't seen a recommended pattern that people agree on. Just do what works for you.
/RU username
A value that specifies the user context under which the task runs.
For the system account, valid values are "", "NT AUTHORITY\SYSTEM", or "SYSTEM".
For Task Scheduler 2.0 tasks, "NT AUTHORITY\LOCALSERVICE", and
"NT AUTHORITY\NETWORKSERVICE" are also valid values.
In .NET development, I normally start off by developing a Console Application, which will run will all logging output to the console window. However, this is 只有 a Console Application when it is run with the command argument /console. When it is run without this parameter, it acts as a Windows Service, which will stay running on my own custom coded scheduled timer.
在过去,我们或多或少总是使用 Windows 服务,但由于越来越多的客户一步一步地转向 Azure,而且从控制台应用程序(作为计划任务部署)到 Azure 中的 WebJob 的转换要比从 Windows 服务部署容易得多,所以我们现在关注计划任务。如果我们遇到限制,我们只需增加 Windows 服务项目并从那里调用相同的逻辑(只要客户使用 OnPrem)。.):)