【问题标题】:Can command line arguments be passed to Service class when using InstallUtil?使用 InstallUtil 时可以将命令行参数传递给服务类吗?
【发布时间】:2020-06-17 16:40:56
【问题描述】:

问题

我试图在安装服务之前将参数从命令行传递给继承 ServiceBase 的服务类。在使用 InstallUtil 运行我的服务安装程序时,我找到了一种接受参数的方法。但是,运行的主要函数 ServiceBase.Run(new Service());在可以访问这些参数之前触发。因此,我不知道如何在运行之前将命令行参数传递给我的 Service() 类。

我使用 ConfigStream 作为静态类从文本配置文件中读取和存储参数。我的目标是在安装程序运行之前从配置文件中导入设置并将它们应用到我的服务类。我希望能够从命令行中的输入指向该配置文件的位置。

尝试的解决方案

我已经尝试将参数应用到安装程序的 OnBeforeInstall 函数中的 ConfigStream 类,但它仍然在主函数之后运行,因此它不会将设置应用到我的服务类。

我也尝试按照微软的教程进行操作,但也没有运气。参数从未传递给 Main。教程:Create Windows Service - Add Optional Params

主类


    public static class MainClass
    {
        ///Function: Main
        ///File: ServiceWrapperV2.cs
        ///Author: Luke Maple
        ///Purpose: Main function of program, start up the service portion of program.
        static void Main(String[] args)
        {
            // Test if input arguments were supplied
            Console.WriteLine("Args: ");
            Console.WriteLine(args);
            if (args.Length > 0)
            {
                // set config location if provided
                // otherwise assume in working directory
                ConfigStream.setConfigstream(args[0]);
            }
            // run service
            ServiceBase.Run(new Service());
        }
    }

安装程序尝试 1


    [RunInstaller(true)]
    public class ServiceWrapperInstaller : Installer
    {
        private ServiceProcessInstaller processInstaller;
        private ServiceInstaller serviceInstaller;

        public ServiceWrapperInstaller()
        {
            //inilizing installer objects 
            processInstaller = new ServiceProcessInstaller();
            serviceInstaller = new ServiceInstaller();

            //Service will use the windows local system acount. Service will be run as admin
            processInstaller.Account = ServiceAccount.LocalSystem;

            //sets service start mode to automatic. service will auto boot on restarts
            serviceInstaller.StartType = ServiceStartMode.Automatic;

            // set service parameters
            // Console.WriteLine(ConfigStream.getSetting("Service Name"));
            serviceInstaller.ServiceName = ConfigStream.getSetting("Service Name");
            // Console.WriteLine("\nService Name: " + serviceInstaller.ServiceName + "\n");
            serviceInstaller.Description = ConfigStream.getSetting("Service Description");

            //passing object to be installed
            Installers.Add(serviceInstaller);
            Installers.Add(processInstaller);
        }

        private void _setConfigLocation()
        {
            if (Context.Parameters.ContainsKey("config"))
            {
                ConfigStream.setConfigstream(Context.Parameters["config"]);
            }
        }

        protected override void OnBeforeInstall(IDictionary savedState)
        {
            _setConfigLocation();
            base.OnBeforeInstall(savedState);
        }
    }

安装程序尝试 2


    [RunInstaller(true)]
    public class ServiceWrapperInstaller : Installer
    {
        private ServiceProcessInstaller processInstaller;
        private ServiceInstaller serviceInstaller;

        public ServiceWrapperInstaller()
        {
            //inilizing installer objects 
            processInstaller = new ServiceProcessInstaller();
            serviceInstaller = new ServiceInstaller();

            //Service will use the windows local system acount. Service will be run as admin
            processInstaller.Account = ServiceAccount.LocalSystem;

            //sets service start mode to automatic. service will auto boot on restarts
            serviceInstaller.StartType = ServiceStartMode.Automatic;

            // set service parameters
            // Console.WriteLine(ConfigStream.getSetting("Service Name"));
            serviceInstaller.ServiceName = ConfigStream.getSetting("Service Name");
            // Console.WriteLine("\nService Name: " + serviceInstaller.ServiceName + "\n");
            serviceInstaller.Description = ConfigStream.getSetting("Service Description");

            //passing object to be installed
            Installers.Add(serviceInstaller);
            Installers.Add(processInstaller);
        }

        protected override void OnBeforeInstall(IDictionary savedState)
        {
            string parameter = "Config";
            Context.Parameters["assemblypath"] = "\"" + Context.Parameters["assemblypath"] + "\" \"" + parameter + "\"";
            base.OnBeforeInstall(savedState);
        }
    }

配置流


    public static class ConfigStream
    {
        // set class properties of ConfigStream
        public static string config { get; private set; } = GlobalVariables.cwd + "\\" + GlobalVariables.configFileName;

        // constructor with config as an argument
        public static void setConfigstream(string config_location)
        {
            string config = config_location;
        }

        ///Function: (static) getSetting
        ///Purpose: get requested value form formatted config file
        public static string getSetting(string setting)
        {
        ...
        }
    ...
    }

【问题讨论】:

    标签: c#


    【解决方案1】:

    你可以试试这样的:

    [RunInstaller(true)]
    public partial class ServiceWrapperInstaller  : Installer
    {
        private const string nameKey = "name";
        private const string displayNameKey = "displayname";
        private const string descriptionKey = "description";
    
        protected override void OnBeforeInstall(IDictionary savedState)
        {
            // Set installer parameters
            SetParameters();
    
            base.OnBeforeInstall(savedState);
        }
    
        private void SetParameters()
        {
            // Set service name
            _serviceInstaller.ServiceName = this.Context.Parameters[nameKey];
    
            // Set the display name (if provided)
            if (Context.Parameters.ContainsKey(displayNameKey))
            {
                _serviceInstaller.DisplayName = this.Context.Parameters[displayNameKey];
            }
    
            // Set the description (if provided)
            if (Context.Parameters.ContainsKey(descriptionKey))
            {
                _serviceInstaller.Description = this.Context.Parameters[descriptionKey];
            }
    
            _serviceInstaller.StartType = ServiceStartMode.Automatic;
            _serviceInstaller.DelayedAutoStart = true;
        }
    }
    

    你可以这样使用它:

    InstallUtil /u /name= /displayname= /description=

    【讨论】:

    • 我使用配置不仅仅是引用名称和描述。该配置还包括有关服务应运行的可执行文件的详细信息。这是在 Service 类中设置的(继承自 ServiceBase)。所以需要在 Main 中实例化 Service 类之前引用和设置配置。我需要能够将参数作为参数传回 Main,或者在 Main 运行之前设置 ConfigStream。
    • 您可以添加任意数量的参数,并将它们作为参数传递给 Main。
    • 你有一个关于如何将参数传递给 main 的例子吗?似乎 main 在 Installer 类之前运行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-22
    • 1970-01-01
    • 1970-01-01
    • 2014-12-25
    • 2013-05-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多