有几个问题可以解决异步控制器的工作原理,但没有一个能完全解决我需要的问题。希望有人已经这样做了,如果我做错了什么,可以告诉我。
我有一个处理配置任务的 Web 应用程序和一个处理运行配置任务的控制台应用程序的组合。我希望能够通过单击按钮立即将控制权返回给用户并在后台执行任务来从 Web 应用程序运行任务。AsyncController 似乎是完美的匹配。两个应用程序都使用 EF6、Unity 依赖注入和 SQL Server 2012 访问同一个数据库。Web 界面的目标是 MVC4 上的 .NET 4.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 类直接运行可执行文件?
非常感谢您的任何见解。