我有一个客户端应用程序(我无法修改,即我只有二进制文件),需要不时运行外部命令,这些命令依赖于很长的资源(约20秒)。
因此,我决定在“CommandServer.exe”应用程序(系统托盘中的单个实例)中为所有资源初始化此资源,并让我的客户端应用程序调用使用.net远程执行的中间“ExecuteCommand.exe”程序服务器上的操作。 “ExecuteCommand.exe”负责在第一次调用时启动服务器,然后将其保持活动状态以加快进一步的命令。
服务:
public interface IMyService
{
void ExecuteCommand(string[] args);
}
“CommandServer.exe”(在资源初始化期间使用WindowsFormsApplicationBase
进行单实例管理+用户友好的初始屏幕):
private void onStartupFirstInstance(object sender, StartupEventArgs e)
{
// Register communication channel
channel = new TcpServerChannel("CommandServerChannel", 8234);
ChannelServices.RegisterChannel(channel, false);
// Register service
var resource = veryLongToInitialize();
service = new MyServiceImpl(resource);
RemotingServices.Marshal(service, "CommandServer");
// Create icon in system tray
notifyIcon = new NotifyIcon();
...
}
中间件“ExecuteCommand.exe”:
static void Main(string[] args)
{
startCommandServerIfRequired();
var channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel, false);
var service = (IMyService)Activator.GetObject(typeof(IMyService), "tcp://localhost:8234/CommandServer");
service.RunCommand(args);
}
由于服务器启动时间很长(初始化所需资源大约需要20秒),因此“{1}”行上的“ExecuteCommand.exe”失败,因为服务器尚不可用。
在拨打service.RunCommand(args)
时,是否有一种优雅的方法可以在接收“服务不可用”之前调整延迟?
NB1:目前我正在解决此问题,在服务器中添加一个互斥锁以指示完全初始化,并在调用service.RunCommand
之前让“ExecuteCommand.exe”等待此互斥锁。
NB2:我没有.net远程处理的背景,也没有推荐的替换者WCF。 (我选择了.net远程处理,因为在运行外部命令时,这个单一镜头问题看起来更容易设置)。
答案 0 :(得分:0)
找到一个更好的解决方案,在应用程序之间添加一些ManualResetEvent
而不是共享Mutex
:
服务器:
private void onStartupFirstInstance(object sender, StartupEventArgs e)
{
// Event to indicate when server is ready
serverReadyEvent = new ManualResetEvent(false);
// Register communication channel
channel = new TcpServerChannel("CommandServerChannel", 8234);
ChannelServices.RegisterChannel(channel, false);
// Register service (even if not fully initialized)
var resources = new ServiceResources();
service = new MyServiceImpl(resources, serverReadyEvent);
RemotingServices.Marshal(service, "CommandServer");
// Finalize service initialization
resources.Initialize();
// Create icon in system tray
notifyIcon = new NotifyIcon();
...
// Indicate server is now ready to process remote commands
serverReadyEvent.Set();
}
服务实施:
class MyServiceImpl : MarshalByRefObject, IMyService
{
public MyServiceImpl(ServiceResources preAllocatedResources, ManualResetEvent serverReadyEvent)
{
this.resources = preAllocatedResources;
this.serverReadyEvent = serverReadyEvent;
}
public override object InitializeLifetimeService()
{
return null;
}
public void ExecuteCommand(string[] args)
{
if (!serverReadyEvent.WaitOne(20000))
{
throw new TimeoutException("Server did not initialized within expected delay.");
}
...
}
private ManualResetEvent serverReadyEvent;
private ServiceResources resources;
}