views:

3748

answers:

7

Besides the service.StartType = ServiceStartMode.Automatic my service does not start after installation

Solution

Inserted this code on my ProjectInstaller

protected override void OnAfterInstall(System.Collections.IDictionary savedState)
{
    base.OnAfterInstall(savedState);
    using (var serviceController = new ServiceController(this.serviceInstaller1.ServiceName, Environment.MachineName))
        serviceController.Start();
}

Thanks to ScottTx and Francis B.

+4  A: 

To start it right after installation, I generate a batch file with installutil followed by sc start

It's not ideal, but it works....

Matt
+4  A: 

You need to add a Custom Action to the end of the 'ExecuteImmediate' sequence in the MSI, using the component name of the EXE or a batch (sc start) as the source. I don't think this can be done with Visual Studio, you may have to use a real MSI authoring tool for that.

Otávio Décio
+3  A: 

Use the .NET ServiceController class to start it, or issue the commandline command to start it --- "net start servicename". Either way works.

ScottTx
+4  A: 

Visual Studio

If you are creating a setup project with VS, you can create a custom action who called a .NET method to start the service. But, it is not really recommended to use managed custom action in a MSI. See this page.

ServiceController controller  = new ServiceController();
controller.MachineName = "";//The machine where the service is installed;
controller.ServiceName = "";//The name of your service installed in Windows Services;
controller.Start();

InstallShield or Wise

If you are using InstallShield or Wise, these applications provide the option to start the service. Per example with Wise, you have to add a service control action. In this action, you specify if you want to start or stop the service.

Wix

Using Wix you need to add the following xml code under the component of your service. For more information about that, you can check this page.

<ServiceInstall 
    Id="ServiceInstaller"  
    Type="ownProcess"  
    Vital="yes"  
    Name=""  
    DisplayName=""  
    Description=""  
    Start="auto"  
    Account="LocalSystem"   
    ErrorControl="ignore"   
    Interactive="no">  
        <ServiceDependency Id="????"/> ///Add any dependancy to your service  
</ServiceInstall>
Francis B.
used your first code block on the solution
Jader Dias
+6  A: 

You can do this all from within your service executable in response to events fired from the InstallUtil process. Override the OnAfterInstall event to use a ServiceController class to start the service.

http://msdn.microsoft.com/en-us/library/system.serviceprocess.serviceinstaller.aspx

ScottTx
This is a nice solution, but still requires the use of the InstallUtil utility. If you're already delivering InstallUtil as part of your installation, this makes the most sense. But, if you want to forego packaging InstallUtil, use the command-line solution.
Matt Davis
+10  A: 

I've posted a step-by-step procedure for creating a Windows service in C# here. It sounds like you're at least to this point, and now you're wondering how to start the service once it is installed. Setting the StartType property to Automatic will cause the service to start automatically after rebooting your system, but it will not (as you've discovered) automatically start your service after installation.

I don't remember where I found it originally (perhaps Marc Gravell?), but I did find a solution online that allows you to install and start your service by actually running your service itself. Here's the step-by-step:

  1. Structure the Main() function of your service like this:

    static void Main(string[] args)
    {
        if (args.Length == 0) {
            // Run your service normally.
            ServiceBase[] ServicesToRun = new ServiceBase[] {new YourService()};
            ServiceBase.Run(ServicesToRun);
        } else if (args.Length == 1) {
            switch (args[0]) {
                case "-install":
                    InstallService();
                    StartService();
                    break;
                case "-uninstall":
                    StopService();
                    UninstallService();
                    break;
                default:
                    throw new NotImplementedException();
            }
        }
    }
  1. Here is the supporting code:

    using System.Collections;
    using System.Configuration.Install;
    using System.ServiceProcess;
    private static bool IsInstalled()
    {
        using (ServiceController controller = new ServiceController("YourServiceName")) {
            try {
                ServiceControllerStatus status = controller.Status;
            } catch {
                return false;
            }
            return true;
        }
    }

    private static bool IsRunning()
    {
        using (ServiceController controller = new ServiceController("YourServiceName")) {
            if (!IsInstalled()) return false;
            return (controller.Status == ServiceControllerStatus.Running);
        }
    }

    private static AssemblyInstaller GetInstaller()
    {
        AssemblyInstaller installer = new AssemblyInstaller(typeof(YourServiceType).Assembly, null);
        installer.UseNewContext = true;
        return installer;
    }
  1. Continuing with the supporting code...

    private static void InstallService()
    {
        if (IsInstalled()) return;

        try {
            using (AssemblyInstaller installer = GetInstaller()) {
                IDictionary state = new Hashtable();
                try {
                    installer.Install(state);
                    installer.Commit(state);
                } catch {
                    try {
                        installer.Rollback(state);
                    } catch { }
                    throw;
                }
        } catch {
            throw;
        }
    }

    private static void UninstallService()
    {
        if ( !IsInstalled() ) return;
        try {
            using ( AssemblyInstaller installer = GetInstaller() ) {
                IDictionary state = new Hashtable();
                try {
                    installer.Uninstall( state );
                } catch {
                    throw;
                }
            }
        } catch {
            throw;
        }
    }

    private static void StartService()
    {
        if ( !IsInstalled() ) return;

        using (ServiceController controller = new ServiceController("YourServiceName")) {
            try {
                if ( controller.Status != ServiceControllerStatus.Running ) {
                    controller.Start();
                    controller.WaitForStatus( ServiceControllerStatus.Running, TimeSpan.FromSeconds( 10 ) );
                }
            } catch {
                throw;
            }
        }
    }

    private static void StopService()
    {
        if ( !IsInstalled() ) return;
        using ( ServiceController controller = new ServiceController("YourServiceName")) {
            try {
                if ( controller.Status != ServiceControllerStatus.Stopped ) {
                    controller.Stop();
                    controller.WaitForStatus( ServiceControllerStatus.Stopped, TimeSpan.FromSeconds( 10 ) );
                }
            } catch {
                throw;
            }
        }
    }
  1. At this point, after you install your service on the target machine, just run your service from the command line (like any ordinary application) with the -install command line argument to install and start your service.

I think I've covered everything, but if you find this doesn't work, please let me know so I can update the answer.

Matt Davis
Note that this solution does not require the use of InstallUtil.exe, so you do not have to deliver it as part of your installation program.
Matt Davis
What's the point with the empty "catch { throw; }" clauses? Also, it is probably not a good idea to hide failures by "Rollback()" as that situation basically leaves the system in an undefined state I guess (you tryied to install a service, failed somewhere in the middle and couldn't undo it). You should at least "show" the user that there is something fishy - or does the Rollback() function write some messages to the console?
Christian.K
The rollback does write data to the console. As for the empty catch blocks, it's a debugging thing. I can put a breakpoint at the throw statement to examine any exceptions that may occur.
Matt Davis
Ah, never thought of that. Thanks.
Christian.K
A: 

Impressive - solved a big problem

John