We have seen previously how to create and deploy a windows service (here and here using a separate installer DLL). What we have seen also is that we can control the start type of the service to specify whether it will be launched manually or automatically. This is very interesting, however this will be used internally by windows only at the next startup of the operating system.
It seems very logical that if we install a service and that we want it to start in an "automatic way", this service shall be running at the end of the installation process, and this without any manual action. We can do this in a very easy way via the installer (I will start again from the previous installer DLL we have created in this post).
Updating the installer
We will need to work at the end of the installation, ie on the "Commit" event. To do so :
-
Right-Click on the setup project and choose "View / Custom Actions"
-
Right-Click on the "Commit" event and choose "Add Custom Action"
-
Choose the "Primary Output from MyWindowsServiceInstallerActions" (from the Application Folder) and click OK
Now our installer DLL will also get called when the commit is occuring.
Starting the event
We can now update the installer class as follows :
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;
using System.IO;
using System.ServiceProcess;
namespace MyWindowsServiceInstallerActions
{
[RunInstaller(true)]
public partial class MyInstaller : Installer
{
protected override void OnCommitted(IDictionary savedState)
{
base.OnCommitted(savedState);
ServiceController service = new ServiceController("MyPersonalService");
service.Start();
}
}
}
Some explanation about the code :
-
We could have decided to do the same treatment on the "Commit" event
-
The ServiceController class let's us manipulate a service (based on the service name, as set in the constructor of the service)
-
If for any reason, the "Start" method doesn't work (problem in the service, event log full, ...) an exception will get raised, and so the installation will fail and rollback.
A more secure implementation would be something like (you must of course include a reference to System.WindowsForms.dll if you want to use the MessageBox class) :
protected override void OnCommitted(IDictionary savedState)
{
base.OnCommitted(savedState);
ServiceController service = new ServiceController("MyPersonalService");
string errorMessage = string.Format("Could not start the service {0}. You should launch it manually"
service.DisplayName);
if ( service.Status == ServiceControllerStatus.Stopped )
{
try
{
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, new TimeSpan(0, 0, 10));
}
catch ( InvalidOperationException )
{
MessageBox.Show(errorMessage);
}
catch ( System.ServiceProcess.TimeoutException )
{
MessageBox.Show(errorMessage);
}
}
}
Note that we use the fully qualified name for the
TimeOutException not to have any ambiguity with the same exception in the
System namespace.