How to make a Windows service with parameters?

后端 未结 5 924
庸人自扰
庸人自扰 2020-12-31 07:33

I have written a Windows service, of which I want to have 1 instance running per customer. This is because the customers each have their own DB with identical schemas; the

相关标签:
5条回答
  • 2020-12-31 07:46

    You basically need to install the service several times, and customise it with it's exe.config file.

    Alternatively, you can have one service that runs different worker threads for each client.

    Update

    exe.Config is an Application Configuration File

    I have no idea how to use that installer component to install several instances of the service, I wasn't aware you could.

    Where we need several instances of one of our services to run on one machine, we actually only install it once, then literally copy the installed folder and change the exe name for the second instance. The second instance is then configured in it's own Application Configuration File.

    0 讨论(0)
  • 2020-12-31 07:49

    Wil Peck wrote a good article about how to install multiple instances of a windows service on a single box. The basic idea is that you have to trick the installer into thinking they are different services by giving them different names.

    Having said that, it seems like it would be easier (and more maintainable) to redesign your database connection code so that it can support multiple worker threads.

    0 讨论(0)
  • 2020-12-31 07:50

    As far as I known it is impossible to provide startup parameters using either ServiceInstaller, ServiceProcessInstaller or installutil. However, it is possible to provide startup parameters using some COM api's from advapi.dll (check the left menu). A complete collection of the required calls can be found here. It's a class (also) called ServiceInstaller that contains the required external methods and some utility methods.

    You'd want to use the utility method InstallAndStart. It accepts a service name, a display name and a path to the executable that represents your Windows service. You can call it like this:

    InstallAndStart("MyService", "My Service For User 1",
                    "c:\\pathtoexe\MyService.exe user1");
    

    If you have the following service the parameter startupParam will receive the value user1.

    class Program : ServiceBase
    {
        private string startupParam;
    
        static void Main(string[] args)
        {
            string arg = args[0];
            ServiceBase.Run(new Program(arg));
        }
    
        public Program(string startupParam)
        {
            this.ServiceName = "MyService";
            this.startupParam = startupParam;
        }
        ...
    }
    
    0 讨论(0)
  • All I wanted was to send one parameter to the service I have created. As it turns out, all you have to do is (carefully!) edit the registry at HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ and add the parameter in ImagePath, after the quotes.

    Eg. ImagePath Value Data: "C:\Program Files\myservice\myservice.exe" param1

    I found the solution in this link http://social.msdn.microsoft.com/Forums/is/csharpgeneral/thread/38242afa-7e40-4c06-975e-aa97d3cc782f

    0 讨论(0)
  • 2020-12-31 08:00

    You can pass parameters to your installer using installutil, for example ServiceName and DisplayName.

    ProjectInstaller.cs

    public partial class ProjectInstaller : Installer
    {
        protected override void OnBeforeInstall(IDictionary savedState)
        {
            SetServiceName();
            base.OnBeforeInstall(savedState);
        }
    
        protected override void OnBeforeUninstall(IDictionary savedState)
        {
            SetServiceName();
            base.OnBeforeUninstall(savedState);
        }
    
        private string AppendParameter(string path, char parameter, string value)
        {
            if (!path.StartsWith("\""))
                path = $"\"{path}\"";
    
            if (value.Contains(" "))
                value = $"\"{value}\"";
    
            return $"{path} -{parameter}{value}";
        }
    
        private void SetServiceName()
        {
            if (Context.Parameters.ContainsKey("ServiceName"))
                serviceInstaller.ServiceName = Context.Parameters["ServiceName"];
    
            if (Context.Parameters.ContainsKey("DisplayName"))
                serviceInstaller.DisplayName = Context.Parameters["DisplayName"];
    
            Context.Parameters["assemblypath"] = AppendParameter(Context.Parameters["assemblypath"], 's', serviceInstaller.ServiceName);
        }
    }
    

    This will append a parameter to the path stored with the service, for example:

    Before: "C:\Service.exe"

    After: "C:\Service.exe" -s"Instance 1"

    You can then read this parameter when you start the service and pass to your services constructor.

    Program.cs

    static void Main(string[] args)
    {
        string serviceName = args.Single(x => x.StartsWith("-s")).Substring("-s".Length);
    
        ServiceBase service = new Service(serviceName);
        ServiceBase.Run(service);
    }
    

    Service.cs

    public partial class Service : ServiceBase
    {
        public Service(string serviceName)
        {
            InitializeComponent();
    
            ServiceName = serviceName;
        }
    }
    

    Usage

    installutil /ServiceName="Instance 1" /DisplayName="Instance 1 Service" "C:\Service.exe"
    installutil /ServiceName="Instance 2" /DisplayName="Instance 2 Service" "C:\Service.exe"
    
    0 讨论(0)
提交回复
热议问题