linux上的单实例dotnetcore cli app

时间:2017-06-15 19:28:22

标签: c# ubuntu .net-core

我对如何为dotnetcore控制台应用程序强制实施单实例策略感兴趣。令我惊讶的是,似乎在这个主题上还没有多少内容。我找到了这个stacko,How to restrict a program to a single instance,但它似乎对我在使用ubuntu的dotnetcore上工作。这里有人这么做吗?

3 个答案:

答案 0 :(得分:2)

@ MusuNaji的解决方案的变化:How to restrict a program to a single instance

    private static bool AlreadyRunning()
    {
        Process[] processes = Process.GetProcesses();
        Process currentProc = Process.GetCurrentProcess();
        logger.LogDebug("Current proccess: {0}", currentProc.ProcessName);
        foreach (Process process in processes)
        {
            if (currentProc.ProcessName == process.ProcessName && currentProc.Id != process.Id)
            {
                logger.LogInformation("Another instance of this process is already running: {pid}", process.Id);
                return true;
            }
        }
        return false;
    }

答案 1 :(得分:1)

由于Linux / MacOS上的互斥检查问题(如上所述),.NET核心上的这一点比应该更难。此外,他们的解决方案并不是很有用,因为所有.NET核心应用程序都是通过CLI运行的,其流程名称为“dotnet”和“dotnet”。如果您在同一台计算机上运行多个.NET核心应用程序,则重复实例检查将错误地触发。

执行此操作同样具有多平台健壮性的简单方法是在应用程序启动时打开要写入的文件,并在最后关闭它。如果文件无法打开,则是由于另一个实例同时运行,您可以在try / catch中处理它。如果文件不首先存在,则使用FileStream打开文件也会创建它。

            try
            {
                lockFile = File.OpenWrite("SingleInstance.lck");
            }
            catch (Exception)
            {
                Console.WriteLine("ERROR - Server is already running. End that instance before re-running. Exiting in 5 seconds...");
                System.Threading.Thread.Sleep(5000);
                return;
            }

答案 2 :(得分:0)

这是我使用命名管道的实现。它支持从第二个实例传递参数。

注意:我没有在Linux或Mac上进行过测试,但从理论上讲应该可以工作。

用法


        public static int Main(string[] args)
        {
            instanceManager = new SingleInstanceManager("8A3B7DE2-6AB4-4983-BBC0-DF985AB56703");
            if (!instanceManager.Start())
            {
                return 0; // exit, if same app is running
            }
            instanceManager.SecondInstanceLaunched += InstanceManager_SecondInstanceLaunched;
            // Initialize app. Below is an example in WPF.
            app = new App();
            app.InitializeComponent();
            return app.Run();
        }
        private static void InstanceManager_SecondInstanceLaunched(object sender, SecondInstanceLaunchedEventArgs e)
        {
            app.Dispatcher.Invoke(() => new MainWindow().Show());
        }

您的复制粘贴代码


    public class SingleInstanceManager
    {
        private readonly string applicationId;
        public SingleInstanceManager(string applicationId)
        {
            this.applicationId = applicationId;
        }
        /// <summary>
        /// Detect if this is the first instance. If it is, start a named pipe server to listen for subsequent instances. Otherwise, send <see cref="Environment.GetCommandLineArgs()"/> to the first instance.
        /// </summary>
        /// <returns>True if this is tthe first instance. Otherwise, false.</returns>
        public bool Start()
        {
            using var client = new NamedPipeClientStream(applicationId);
            try
            {
                client.Connect(0);
            }
            catch (TimeoutException)
            {
                Task.Run(() => StartListeningServer());
                return true;
            }
            var args = Environment.GetCommandLineArgs();
            using (var writer = new BinaryWriter(client, Encoding.UTF8))
            {
                writer.Write(args.Length);
                for (int i = 0; i < args.Length; i++)
                {
                    writer.Write(args[i]);
                }
            }
            return false;
        }
        private void StartListeningServer()
        {
            var server = new NamedPipeServerStream(applicationId);
            server.WaitForConnection();
            using (var reader = new BinaryReader(server, Encoding.UTF8))
            {
                var argc = reader.ReadInt32();
                var args = new string[argc];
                for (int i = 0; i < argc; i++)
                {
                    args[i] = reader.ReadString();
                }
                SecondInstanceLaunched?.Invoke(this, new SecondInstanceLaunchedEventArgs { Arguments = args });
            }
            StartListeningServer();
        }
        public event EventHandler<SecondInstanceLaunchedEventArgs> SecondInstanceLaunched;
    }
    public class SecondInstanceLaunchedEventArgs
    {
        public string[] Arguments { get; set; }
    }

单元测试

[TestClass]
    public class SingleInstanceManagerTests
    {
        [TestMethod]
        public void SingleInstanceManagerTest()
        {
            var id = Guid.NewGuid().ToString();
            var manager = new SingleInstanceManager(id);
            string[] receivedArguments = null;
            var correctArgCount = Environment.GetCommandLineArgs().Length;
            manager.SecondInstanceLaunched += (sender, e) => receivedArguments = e.Arguments;
            var instance1 = manager.Start();
            Thread.Sleep(200);
            var manager2 = new SingleInstanceManager(id);
            Assert.IsFalse(manager2.Start());
            Thread.Sleep(200);
            Assert.IsTrue(instance1);
            Assert.IsNotNull(receivedArguments);
            Assert.AreEqual(correctArgCount, receivedArguments.Length);
            var receivedArguments2 = receivedArguments;
            var manager3 = new SingleInstanceManager(id);
            Thread.Sleep(200);
            Assert.IsFalse(manager3.Start());
            Assert.AreNotSame(receivedArguments, receivedArguments2);
            Assert.AreEqual(correctArgCount, receivedArguments.Length);
        }
    }