从ASP.net运行Windows计划任务

8

我有一个Windows定时任务,每小时运行一次数据库导入过程,但我希望用户能够通过在运行在Windows Server 2003上的IIS6中的ASP.net仪表板中点击按钮来启动它。

以下代码在后台完美地工作...

var proc = new Process
            {
                StartInfo =
                    {
                        UseShellExecute = false,
                        FileName = @"C:\Windows\System32\schtasks.exe",
                        Arguments = "/run /tn Loader",
                        RedirectStandardError = true,
                        RedirectStandardOutput = true,
                        CreateNoWindow = true
                    }
            };
proc.Start();
proc.WaitForExit();

如果应用程序池的身份设置为本地系统(并不理想!),则可以启动任务。如果将其保留为网络服务,则任务不会启动。因此,这可能是权限问题。

ASP.net有没有办法在服务器上启动计划任务而不以本地系统运行应用程序?如果没有,有什么好的替代方案呢?

更新:如果SO上没有人知道,我想这是不可能的,所以我会采用我的想法,让我的Web应用程序将请求写入数据库表(同时作为审计日志),并创建第二个任务来轮询该表并启动主任务。


为什么你不调用这个任务在你的Web应用程序中将要调用的内容?为什么你想运行任务,而不是任务的目标? - user172163
1
好问题。1 我需要任务以特定用户身份运行,而且 2 它不能与每小时计划任务同时运行,Windows 计划程序很方便地不会启动已经手动启动的任务。虽然我没有详细探索过这个选项。 - Chris B
4个回答

6

更新您的计划任务以触发特定事件。然后,在单击按钮时,使您的网站记录该事件,从而启动您的计划任务。

例如:在我的安装程序中,我为我的程序创建了一个事件日志源,因为创建源需要管理员权限(您也可以使用命令行创建源

  if (EventLog.SourceExists("MyApp"))
  {
      EventLog.CreateEventSource("MyApp", "Application");
  }

然后在我的应用程序中,当按钮被点击时,我创建一个事件日志条目。

private void btnOpenOtherApp_Click (object sender, EventArgs e) 
{
    try 
    {
        var log = new EventLog
        {
            Source = "MyApp"
        };
        log.WriteEntry("Start MyOtherApp", EventLogEntryType.Information, 1337);
    } 
    catch (Exception ex) 
    {
        ...   
    }
}

任务计划程序设置为在事件记录时打开MyOtherApp。 事件查看器


这将需要“更改注册表”以获得适当的写入权限。 - highwingers
1
我的不行。如果你将log.source设置为“.NET Runtime”,那么就没问题了。虽然我将其设置为我的应用程序名称,因为我设置了我的安装程序以将应用程序添加为事件日志源。如果您需要,我可以发布一些代码。 - basher
是的,你说得对。我刚刚尝试了一下,确实有效。不过,我想知道如何创建一个新的源代码文件...能否贴一些代码? - highwingers

1
你需要在Windows中拥有管理员用户。以下代码可以帮助你调用任务:
var securePass = new System.Security.SecureString();
foreach (char c in "my_password")
{
    pass.AppendChar(c);
}

var proc = new Process
{
    StartInfo =
    {
        UseShellExecute = false,
        FileName = @"C:\Windows\System32\schtasks.exe",
        Arguments = "/run /tn Loader",
        UserName = "myAdminUser", //NEW
        Password = securePass, //NEW
        RedirectStandardError = true,
        RedirectStandardOutput = true,
        CreateNoWindow = true
    }
};
proc.Start();
proc.WaitForExit();

如果你的应用程序需要以SYSTEM账户运行,你可以使用以下参数:
如果/RU用户名和/RP密码参数与当前登录的用户匹配,任务将交互式运行(在前台可见)。
对于系统账户,/RU用户名可以写为“”,“NT AUTHORITY\SYSTEM”或“SYSTEM”,不需要密码。系统账户具有对本地计算机的完全访问权限,但在网络上没有任何其他计算机(或映射驱动器)的权限。
来源:http://ss64.com/nt/schtasks.html

ProcessStartInfo.Password 是 SecureString 类型而不是字符串,因此此代码无法编译。 - Dan

0

如果使用第三方调度程序服务,例如Quartz.NET不是一个选项,并且更改权限也不被允许(在任何情况下都不是一个好主意),另一个可能性是编写一个帮助器Windows服务作为ASP.NET应用程序和Windows调度程序之间的桥梁。您将在DB中存储任务列表,事件序列如下:

  1. 当您需要运行任务时,在ASP.NET GUI中为该任务设置标志
  2. Helper服务按计划运行以检查给定间隔的DB-查看标志,启动任务,重置标志。

哦,还有一些库(例如http://taskscheduler.codeplex.com/和其他)可以包装Window任务计划程序,因此您不必直接执行它们,而是以良好的托管方式执行它们。


0

1
这是一种hack的方法。更好的方式是使用诸如http://atrigger.com之类的调度服务。 - user172163

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接