TheLethalCoder
TheLethalCoder

Reputation: 6744

Can the Service Installer class run in a different Assembly?

I have a custom Installer class that is used when installing my Windows Service. Stripped down to the necessary details the class looks like this.

[RunInstaller(true)]
public class MyWindowsServiceInstaller : Installer
{
    public MyWindowsServiceInstaller()
    {
        ServiceProcessInstaller processInstaller = new ServiceProcessInstaller();
        ServiceInstaller serviceInstaller = new ServiceInstaller();

        processInstaller.Account = ServiceAccount.LocalSystem;

        serviceInstaller.DisplayName = Program.ServiceDetails.Name;
        serviceInstaller.Description = Program.ServiceDetails.Description;

        //Must be the same as what was set in Program's constructor
        serviceInstaller.ServiceName = Program.ServiceDetails.Name;

        Installers.Add(processInstaller);
        Installers.Add(serviceInstaller);
    }
}

The service is then installed through code by calling the following class, depending on arguments passed into the service, like so. This is called from inside of Main.

using (ServiceHandler serviceHandler = new ServiceHandler(program.ModuleName, typeof(Program).Assembly))
{
    serviceHandler.InstallService();
}

Where the ServiceHandler class is (again stripped down to remove noise).

public class ServiceHandler : IDisposable
{
    private ServiceController _serviceController;
    private AssemblyInstaller _assemblyInstaller;

    public ServiceHandler(string serviceName, Assembly assembly)
    {
        _serviceController = new ServiceController(serviceName);

        _assemblyInstaller = new AssemblyInstaller(assembly, null);
        _assemblyInstaller.UseNewContext = true;
    }

    public void InstallService()
    {
        if (IsServiceInstalled())
        {
            return;
        }

        IDictionary state = new Hashtable();
        try
        {
            _assemblyInstaller.Install(state);
            _assemblyInstaller.Commit(state);
        }
        catch
        {
            try
            {
                _assemblyInstaller.Rollback(state);
            }
            catch { }
            throw;
        }
    }

    public bool IsServiceInstalled()
    {
        try
        {
            ServiceControllerStatus status = _serviceController.Status;
        }
        catch
        {
            return false;
        }

        return true;
    }
}

However, at the moment all of our services use the same MyWindowsServiceInstaller but copied into each project separately. To resolve this I was going to move that class to a common assembly with some other functionality (and remove the coupling of the class with Program) but I'm not sure if it's possible to have the Installer in another assembly.

Is this possible? If so how do I go about it?


I imagine another problem with my approach is the typeof(Program).Assembly call to create the ServiceHandler but I'm not sure.

Upvotes: 2

Views: 543

Answers (1)

csa
csa

Reputation: 341

Installer looks into the assembly and looking for [RunInstaller(true)] attribute. Only think you should do: Mark for installer witch is your installer class. Put an inherited empty class into your main assembly.

Common Assembly:

//[RunInstaller(true)] <<-- REMOVE this
public class MyWindowsServiceInstaller : Installer
{
   public MyWindowsServiceInstaller(){
    ServiceProcessInstaller processInstaller = new 
    ServiceProcessInstaller();
    ServiceInstaller serviceInstaller = new ServiceInstaller();

    processInstaller.Account = ServiceAccount.LocalSystem;

    serviceInstaller.DisplayName = Program.ServiceDetails.Name;
    serviceInstaller.Description = Program.ServiceDetails.Description;

    //Must be the same as what was set in Program's constructor
    serviceInstaller.ServiceName = Program.ServiceDetails.Name;

    Installers.Add(processInstaller);
    Installers.Add(serviceInstaller);
    }
}

Main assembly

[RunInstaller(true)] // <<-- put it here
public class ProjectInstaller : MyWindowsServiceInstaller { }

Upvotes: 4

Related Questions