Asp.net mvc 4 用于运行控制台应用程序的AsyncController

Asp.net mvc 4 用于运行控制台应用程序的AsyncController,asp.net-mvc-4,process,console-application,executable,asynccontroller,Asp.net Mvc 4,Process,Console Application,Executable,Asynccontroller,有几个问题涉及异步控制器的工作,但没有一个完全涉及我需要的。希望有人已经这样做了,如果我做错了,可以告诉我 我有一个处理配置任务的web应用程序和一个处理运行配置任务的控制台应用程序。我希望能够通过单击一个按钮从web应用程序运行任务,该按钮上的控件将立即返回给用户,任务将在后台执行。AsyncController似乎是一对完美的组合。两个应用程序都使用EF6、Unity dependency injection和SQL Server 2012访问相同的数据库。Web界面的目标是MVC4上的.N

有几个问题涉及异步控制器的工作,但没有一个完全涉及我需要的。希望有人已经这样做了,如果我做错了,可以告诉我

我有一个处理配置任务的web应用程序和一个处理运行配置任务的控制台应用程序。我希望能够通过单击一个按钮从web应用程序运行任务,该按钮上的控件将立即返回给用户,任务将在后台执行。AsyncController似乎是一对完美的组合。两个应用程序都使用EF6、Unity dependency injection和SQL Server 2012访问相同的数据库。Web界面的目标是MVC4上的.NET4.5

我可以很好地运行控制台应用程序,不会出现任何问题。我还可以使用下面的代码从web界面触发运行。唯一的问题是,当通过web应用程序触发时,任务将运行到我可以在日志Nlog中看到的某个点,但它将停止执行,直到我重新生成解决方案-解决方案包含这两个应用程序,这也将替换正在运行的.exe。当我直接运行控制台应用程序时,没有任何暂停

这是我第一次使用Task,我对Process类也有点害羞。如果我做了一些非常愚蠢的事,请不要太苛刻

以下是控制器的代码:

public class TaskRunnerController : AsyncController
{
    private readonly ITaskProcessService _taskProcessService;
    private readonly IAuthenticationContext _context;
    private readonly IServiceBase<Task> _taskService;

    public TaskRunnerController(ITaskProcessService taskProcessService,
        IAuthenticationContext context,
        IServiceBase<Task> taskService)
    {
        _taskProcessService = taskProcessService;
        _context = context;
        _taskService = taskService;
    }

    private string TaskRunnerExe
    {
        get
        {
            var setting = ConfigurationManager.AppSettings["TaskRunner.Exe"];
            Guard.Against<ConfigurationErrorsException>(string.IsNullOrEmpty(setting), "Missing configuration setting: TaskRunner.Exe");
            return setting;
        }
    }

    [CustomAuthorize(typeof(CanRun))]
    public ActionResult RunTaskAsync(long id)
    {
        var task = _taskService.Find(i => i.TaskId == id);
        Guard.AgainstLoad(task, id);
        var fileInfo = new FileInfo(TaskRunnerExe);
        Guard.Against<ConfigurationErrorsException>(!fileInfo.Exists, "TaskRunner could not be found at specified location: {0}", TaskRunnerExe);
        var taskProcess = _taskProcessService.Schedule(task, _context.Principal.Identifier);
        AsyncManager.OutstandingOperations.Increment();
        System.Threading.Tasks.Task.Factory.StartNew(() =>
        {
            ProcessStartInfo info = new ProcessStartInfo(fileInfo.FullName,
                string.Format("{0} {1}", task.TaskId, taskProcess.TaskProcessId));
            info.UseShellExecute = false;
            info.RedirectStandardInput = true;
            info.RedirectStandardOutput = true;
            info.CreateNoWindow = true;
            var process = new Process { StartInfo = info, EnableRaisingEvents = true };
            process.Exited += (sender, e) =>
            {
                AsyncManager.OutstandingOperations.Decrement();
            };
            process.Start();
        });
        if (_context.Principal.HasPermission<CanViewList>())
            return RedirectToAction("Index", "Tasks");
        return RedirectToAction("Index", "Home");
    }

    public ActionResult RunTaskProgress()
    {
        return View();
    }

    public ActionResult RunTaskCompleted()
    {
        return Content("completed", "text/plain");
    }
}
依赖项:

taskProcessService:每个任务运行事件的存储库 上下文:保留有关当前用户的信息 taskService:任务的存储库 控制台应用程序.exe在完全完成后退出。正如我所提到的,当通过web应用程序调用时,任务只有在我重新构建应用程序时才会完成——此时,它完成了它应该做的一切——它似乎一直在工作,只是在过程中的某个点停止了日志记录或报告

也许这很重要-我在没有异步控制器的情况下尝试了另一次,但使用相同的设置-运行流程,包装在具有相同最终效果的任务中。当主线程返回池时,我认为进程被终止了,这就是为什么我尝试使用AsyncController

如果我打开任务管理器,我可以看到exe的进程处于空闲状态。应用程序会记录到某一点的进度,但只是停留在那里。这是VS的问题吗?我正在使用VS2012

我将流程包装成任务是错误的吗?有没有办法通过Task类和Action类直接运行可执行文件


非常感谢您提供的任何见解。

很可能由于辅助进程结束,应用程序正在终止。完成后,IIS将终止在请求线程下运行的所有线程或子进程


因此,做你正在做的事情是不可行的。您可以将控制台应用程序移动到计划任务,然后从web应用程序触发计划任务

这方面的更新。我现在已经确定,进程启动的exe控制台应用程序确实在后台正常运行。然而,由于某种原因,当它由于某种原因被重定向时,它停止写入标准输出流。我已经更新了正在运行的控制台应用程序,以便它在运行过程中直接将日志添加到数据库中的任务中,并且工作正常。我可以在网站上实时跟踪任务的进度

我还验证了控制台应用程序和网站都是托管代码,没有内存泄漏。一旦exe完成,它将从进程列表中删除,正如我所期望的那样


重点是,上面的代码可以工作,但我仍然不确定为什么没有写入标准输出。这可能是因为在控制台应用程序中,我使用依赖注入的Nlog通过ConsoleTarget写入控制台。

感谢insight Erik。这正是我所想的。我希望在某个时候通过windows服务运行这些任务,但现在我只想让它工作。但令人费解的是,我可以看到任务管理器中的进程没有被终止——进程id在启动时会被记录下来,这样我就可以判断它是正确的。退出时的主线程是否只是终止任务的线程,而不是包装进程?如前所述,当重建时,进程将恢复并像正常情况一样完成。只是事后想了想:我的印象是AsyncController应该正好满足这个目的——踢长时间运行的进程,并将请求线程返回池中。当进程完成时,从池中取出另一个线程来处理响应。这不是正在发生的吗?有点。您仍然需要等待过程结束。您不能结束请求,否则任务树将被清理。线程返回到池中,但您仍在等待任务完成。