Installing Windows Service with Configurable Name

G

Guest

Hi All

I would like to install the same Windows Service project on the same server
under different names, one for each customer. I have been able to do it but
I would like an expert opinion as to whether my solution is robust or whether
there is a better way to do it.

What I've been trying to do is to create a core project with different
extension projects, one for each customer. I wanted to create a different
Setup project for each customer where each Setup project included the primary
outputs of the core project and the appropriate customer extension project.

In the end I found I needed to create 4 projects:
1) The Core project, with abstract base classes that are extended by the
customer extension projects.
2) The Customer Extension projects, each one of which contains classes that
inherit and extend the base classes in the Core project. These Customer
Extension projects reference the Core project.
3) An EntryPoint project that provides the entry point of the application.
It looks for a customer extension assembly in a sub-folder of the application
folder and loads it, if found. It then starts the Windows service. The
Windows service uses the classes in the customer extension that has been
loaded. This project also references the Core project.
4) The Customer Setup projects. Each one installs the application as a
different Windows service. Each setup project includes the primary outputs
of the EntryPoint project and the appropriate Customer Extension project.

I wanted to include only the minimum functionality in the Customer Extension
projects so it would be easy for junior developers to add new customers
without problems. As a result, I tried to find a way of including just one
Service.cs class and one Installer.cs class in the EntryPoint project, and
configuring them so each Customer Setup project would install the application
with a different service name.

As far as I could see I would need to make the following three properties of
the Installer class configurable: the ServiceName, the DisplayName and the
Description. I would also need to make the following property of the Service
class configurable: ServiceName.

Initially I tried reading the properties from a config file but it appeared
it was not possible for the Installer class to read the config file during
installation. I then tried reading the properties from a resx file. That
seemed to work. So now I've added a resx file to each Customer Extension
project. Each resx file contains 3 entries: ServiceName, DispalyName,
Description. Each Customer Setup file copies the resx file from the
appropriate Customer Extension folder to the application folder. If I run
the MSI files created from each Customer Setup project I can install the same
application on the same server with different customer extensions as
different Windows services.

Here is the code in the Installer class that sets the three configurable
properties (where the installer class is called ServiceInstaller and
MiscLiterals is a static class containing all the string literals in the
project. serviceInstaller1 is an instance of
System.ServiceProcess.ServiceInstaller):

[RunInstaller(true)]
public partial class ServiceInstaller : Installer
{
public ServiceInstaller()
{
InitializeComponent();

// Read service properties from the resx file (will override the
properties specified in the Designer).
// Assumption: The resx file has been copied from the customer extension
project to the JBEEntryPoint
// application folder by the service setup project.
Assembly assy = Assembly.GetExecutingAssembly();
string resxPath = Path.GetDirectoryName(assy.Location);
string resxFile = Path.Combine(resxPath,
MiscLiterals.ServicePropertiesFile);

try
{
ResXResourceReader rsxr = new ResXResourceReader(resxFile);
foreach (DictionaryEntry de in rsxr)
{
switch (de.Key.ToString().ToLower())
{
case "servicename":
this.serviceInstaller1.ServiceName = de.Value.ToString();
break;
case "displayname":
this.serviceInstaller1.DisplayName = de.Value.ToString();
break;
case "description":
this.serviceInstaller1.Description = de.Value.ToString();
break;
}
}
rsxr.Close();
}
catch (Exception xcp)
{
//Do nothing for the moment.
}
}
}
}


Here is the code in the Service class that sets the ServiceName property
(where the service class is called JBEService, Plugins is a structure
containing the classes from the Customer Extension assembly that was loaded,
and Logging is a similar static class to MiscLiterals):

partial class JBEService : ServiceBase
{

// Initialize the trace sources.
static TraceSource _mainLogSource = new
TraceSource(Logging.MainTraceSource);
static TraceSource _inwardsLogSource = new
TraceSource(Logging.InwardsTraceSource);
static TraceSource _outwardsLogSource = new
TraceSource(Logging.OutwardsTraceSource);

Plugins _pluginsLoaded;
public JBEService(Plugins pluginsLoaded)
{
InitializeComponent();

_pluginsLoaded = pluginsLoaded;

// Read service name from the resx file (will override the name specified
in the Designer).
// Assumption: The resx file has been copied from the customer extension
project to the JBEEntryPoint
// application folder by the service setup project.
Assembly assy = Assembly.GetExecutingAssembly();
string resxPath = Path.GetDirectoryName(assy.Location);
string resxFile = Path.Combine(resxPath,
MiscLiterals.ServicePropertiesFile);
try
{
ResXResourceReader rsxr = new ResXResourceReader(resxFile);
foreach (DictionaryEntry de in rsxr)
{
if (de.Key.ToString().ToLower() == "servicename")
{
this.ServiceName = de.Value.ToString();
break;
}
}
rsxr.Close();
}
catch (Exception xcp)
{
string errMessage = string.Format("Exception while attempting to read
service name from resource file: {0}",
xcp.Message);
_mainLogSource.TraceEvent(TraceEventType.Error, 605, errMessage);
}
}

....More code, such as OnStart, OnStop, down here....

As I mentioned at the top of this post, this seems to work but I'm not sure
how robust it is. One of our system admins has told me a version of the
application installed on a Windows 2000 server did not auto restart when they
rebooted the server, although the service was set to auto start. I haven't
had any problems with the application auto restarting when testing on a
Windows XP SP2 machine, though. The application was developed using .NET 2.0.

Cheers
Simon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top