最好的选择是查看该方法是否支持任何类型的合作取消。
但是,如果这不可能,那么取消像这样的长时间运行的进程的下一个最佳选择是使用运行长时间运行的进程的第二个可执行文件,然后通过某种形式的 IPC 与该第二个可执行文件通信(命名管道上的 WCF 非常适合内部-machine IPC)“代理”所有呼叫。当您需要取消进程时,您可以终止第二个代理 exe,所有句柄都将被正确释放(在哪里Thread.Abort()
不会)。
这是一个完整的例子。有 3 个文件,一个在两个可执行文件之间共享的公共库,其中包含代理的接口和实现,一个托管应用程序和您的客户端应用程序。托管应用程序和公共库可能会合并到一个程序集中。
库数据.dll
//ISapProxy.cs
using System.Collections.Generic;
using System.ServiceModel;
namespace LibraryData
{
[ServiceContract]
public interface ISapProxy
{
[OperationContract]
List<SapData> QueryData(string query);
[OperationContract]
void Close();
}
}
//SapProxy.cs
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
namespace LibraryData
{
public class SapProxy : ISapProxy
{
public List<SapData> QueryData(string query)
{
Thread.Sleep(new TimeSpan(0, 0, 5)); //represents time + cpu intensive method
return new List<SapData>();
}
public void Close()
{
Application.Exit();
}
}
}
//SapData.cs
using System.Runtime.Serialization;
namespace LibraryData
{
[DataContract]
public class SapData
{
}
}
主机应用程序
//Program.cs
using LibraryData;
using System;
using System.ServiceModel;
using System.Windows.Forms;
namespace HostApp
{
class Program
{
[STAThread]
static void Main(string[] args)
{
System.Diagnostics.Debugger.Launch();
if (args.Length > 0)
{
var uri = new Uri("net.pipe://localhost");
using (var host = new ServiceHost(typeof(SapProxy), uri))
{
//If a client connection fails, shutdown.
host.Faulted += (obj, arg) => Application.Exit();
host.AddServiceEndpoint(typeof(ISapProxy), new NetNamedPipeBinding(), args[0]);
host.Open();
Console.WriteLine("Service has started and is ready to use.");
//Start a message loop in the event the service proxy needs one.
Application.Run();
host.Close();
}
}
}
}
}
你的程序.exe
using LibraryData;
using System;
using System.Diagnostics;
using System.ServiceModel;
using System.Threading.Tasks;
namespace SandboxConsole
{
class Program
{
static void Main(string[] args)
{
var connectionName = Guid.NewGuid().ToString();
ProcessStartInfo info = new ProcessStartInfo("HostApp", connectionName);
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
var proxyApp = Process.Start(info);
//Blocks till "Service has started and is ready to use." is printed.
proxyApp.StandardOutput.ReadLine();
var sapProxyFactory = new ChannelFactory<ISapProxy>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/" + connectionName));
Task.Factory.StartNew(() =>
{
var sapProxy = sapProxyFactory.CreateChannel();
try
{
var result = sapProxy.QueryData("Some query");
//Do somthing with the result;
}
finally
{
sapProxy.Close();
}
});
Console.WriteLine("ready");
//If you hit enter here before the 5 second pause in the library is done it will kill the hosting process forcefully "canceling" the operation.
Console.ReadLine();
proxyApp.Kill();
Console.ReadLine();
}
}
}
我无法完全消除的一个错误是,如果您“快速失败”客户端应用程序(例如通过单击 Visual Studio 中的停止图标),它永远没有机会告诉托管应用程序关闭。