C# 当在客户端超时时取消控制器操作时,ASP.NET MVC3应用程序将如何调用某些代码?
有一个ASP.NET MVC3应用程序,其中一些控制器操作使用外部机制来处理输入数据。输入数据首先保存到一个临时文件中,然后运行一个外部程序,并在命令行中传递临时文件的路径。这是使用C# 当在客户端超时时取消控制器操作时,ASP.NET MVC3应用程序将如何调用某些代码?,c#,asp.net,.net,asp.net-mvc-3,C#,Asp.net,.net,Asp.net Mvc 3,有一个ASP.NET MVC3应用程序,其中一些控制器操作使用外部机制来处理输入数据。输入数据首先保存到一个临时文件中,然后运行一个外部程序,并在命令行中传递临时文件的路径。这是使用System.Diagnostics.Processclass完成的 外部程序通常会很快退出—比启动后的一秒钟要早,因此没有问题,只需使用Process.WaitForProcessExit()和dispose TheProcess对象等待其完成即可 如果外部程序挂起并且没有及时退出,那么它会变得更加困难。这种情况很
System.Diagnostics.Process
class完成的
外部程序通常会很快退出—比启动后的一秒钟要早,因此没有问题,只需使用Process.WaitForProcessExit()
和dispose TheProcess
对象等待其完成即可
如果外部程序挂起并且没有及时退出,那么它会变得更加困难。这种情况很少发生,但当它发生时,Process.WaitForProcessExit()
也会挂起,控制器操作会运行一段时间,但随后客户端超时,控制器操作被取消,但我无法找到会导致外部程序强制终止的方法。我当然可以使用Process.Kill()
,但我必须将此调用连接到某个地方,以便在由于客户端超时而取消控制器操作时调用它
我试图重写Controller.OnException(),但在这种情况下似乎没有调用它
如何更改ASP.NET MVC3代码,使其在客户端超时时调用某些自定义代码(如外部程序终止)?我已根据基于任务的注释检查了解决方案-这在执行阻塞操作时非常有用。您可以避免阻塞调用
WaitForProcessExit()
,并创建更简单的解决方案
解决方案是以包装器的形式
public enum SafeProcessState { Exit = 1, Killed = 2 }
public class SafeProcess
{
private readonly Process process;
private readonly Func<bool> killPredicate;
public SafeProcess(Func<bool> killPredicate, Process process)
{
this.killPredicate = killPredicate;
this.process = process;
}
public async Task<SafeProcessState> WaitAsync()
{
var state = SafeProcessState.Exit;
while (true)
{
await Task.Delay(100);
if (this.killPredicate())
{
state = SafeProcessState.Killed;
if (this.process.HasExited == false)
{
this.process.Kill();
}
break;
}
else if (this.process.HasExited)
{
break;
}
}
return state;
}
}
它基本上(每100毫秒检查一次)等待进程退出或客户端断开连接,并返回有关退出原因的信息-exit
或Killed
如果用户已断开连接,则终止进程
使用
async/await Task.Delay
可以确保释放执行线程,这样做100毫秒纯粹是出于性能原因
注意:您可以进入终止已经退出的进程的场景,这将引发异常(进程和asp net操作之间存在并发)。您需要在进程执行和.Kill()
之间进行一些同步。。。或者,您可以将呼叫包装为try/catch。如果您选择“尝试/捕获-忘记”方案,一定要记录情况。解决方案不太清楚,但如何:您可以找到一种方法将
进程。WaitForProcessExit()
转换为常见的任务
。然后可以使用var timeoutTask=Task.Delay(30*1000);如果(wait Task.WhenAny(Task,timeoutTask)=timeoutTask){…}
@vasily.sib,则代码似乎没有外部进程的“强制终止”。
public async ...... ActionName()
{
var process = Process.Start("....");
var wrapper = new SafeProcess(() => HttpContext.Current.Response.IsClientConnected == false, process);
var state = await wrapper.WaitAsync();
}