Asp.net mvc 4 用于运行控制台应用程序的AsyncController
有几个问题涉及异步控制器的工作,但没有一个完全涉及我需要的。希望有人已经这样做了,如果我做错了,可以告诉我 我有一个处理配置任务的web应用程序和一个处理运行配置任务的控制台应用程序。我希望能够通过单击一个按钮从web应用程序运行任务,该按钮上的控件将立即返回给用户,任务将在后台执行。AsyncController似乎是一对完美的组合。两个应用程序都使用EF6、Unity dependency injection和SQL Server 2012访问相同的数据库。Web界面的目标是MVC4上的.NET4.5 我可以很好地运行控制台应用程序,不会出现任何问题。我还可以使用下面的代码从web界面触发运行。唯一的问题是,当通过web应用程序触发时,任务将运行到我可以在日志Nlog中看到的某个点,但它将停止执行,直到我重新生成解决方案-解决方案包含这两个应用程序,这也将替换正在运行的.exe。当我直接运行控制台应用程序时,没有任何暂停 这是我第一次使用Task,我对Process类也有点害羞。如果我做了一些非常愚蠢的事,请不要太苛刻 以下是控制器的代码: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
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应该正好满足这个目的——踢长时间运行的进程,并将请求线程返回池中。当进程完成时,从池中取出另一个线程来处理响应。这不是正在发生的吗?有点。您仍然需要等待过程结束。您不能结束请求,否则任务树将被清理。线程返回到池中,但您仍在等待任务完成。