.net remoting - 等待服务初始化的更好解决方案?

时间:2014-06-02 10:35:14

标签: remoting

上下文

我有一个客户端应用程序(我无法修改,即我只有二进制文件),需要不时运行外部命令,这些命令依赖于很长的资源(约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远程处理,因为在运行外部命令时,这个单一镜头问题看起来更容易设置)。

1 个答案:

答案 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;
}