Window服务程序里面都会有ProjectInstaller这个安装类(此类继承Installer),里面设置程序名称、描述、启动类型等等。但直接写在程序里面不够灵活。笔者曾经遇到过一个服务程序在同一台机跑2个实例这样的需求。如果服务名称相同,系统是不允许安装的。怎么办?难道改程序然后重新编译吗?显然不是最好的方案。如果把程序名称写到配置里面来不是更好吗? 废话少说,直接上代码。
一、定义配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<InstallerSettings>
<ServiceName>ServiceName</ServiceName>
<DisplayName>DisplayName</DisplayName>
<Description>Description</Description>
<!--Automatic = 2,Manual = 3,Disabled = 4-->
<StartType>2</StartType>
<!--启动依赖项,多个逗号分隔-->
<DependedOn>MSSQLSERVER</DependedOn>
</InstallerSettings>
保存为Installer.config。切记不能放在app.config里面。为什么?自己想一想。
二、读取配置文件,我定义了一个类:
/// <summary>
/// 安装配置类
/// </summary>
public class InstallerSettings
{
public string DisplayName;
public string Description;
public string ServiceName;
/// <summary>
/// Automatic = 2,Manual = 3,Disabled = 4
/// </summary>
public int StartType;
public string[] DependedOn;
public InstallerSettings(string settingsFilePath)
{
Load(settingsFilePath);
}
private void Load(string settingsFilePath)
{
if (!File.Exists(settingsFilePath))
{
throw new FileNotFoundException(string.Format("Can't find installer settings file({0}).", settingsFilePath));
}
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(settingsFilePath);
XmlNode root = xmlDoc.DocumentElement;
if (root != null)
{
string value;
foreach (XmlNode subXmlNode in root.ChildNodes)
{
if (XmlNodeType.Element == subXmlNode.NodeType)
{
value = subXmlNode.InnerText.Trim();
switch (subXmlNode.Name.ToLower())
{
case "servicename":
this.ServiceName = value;
break;
case "displayname":
this.DisplayName = value;
break;
case "description":
this.Description = value;
break;
case "starttype":
this.StartType = int.Parse(value);
break;
case "dependedon":
if (!string.IsNullOrEmpty(value))
{
this.DependedOn = value.Split(',');
}
else
{
this.DependedOn = new string[0];
}
break;
}
}
}
}
if (string.IsNullOrEmpty(this.ServiceName))
{
throw new ConfigurationErrorsException(string.Format("ServiceName is not allow be null or empty.(Settings File: {0})" + settingsFilePath));
}
if (this.StartType == 0)
{
this.StartType = 2;
}
}
}
三、调用:
/// <summary>
/// 服务安装类
/// </summary>
[RunInstaller(true)]
public class WindowServiceInstaller : Installer
{
private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
private System.ServiceProcess.ServiceInstaller serviceInstaller1;
public WindowServiceInstaller()
{
InitializeComponent();
string path = System.Environment.CurrentDirectory + "\\Installer.config";
InstallerSettings settings = new InstallerSettings(path);
this.serviceInstaller1.ServiceName = settings.ServiceName;
this.serviceInstaller1.DisplayName = settings.DisplayName;
this.serviceInstaller1.Description = settings.Description;
this.serviceInstaller1.StartType = (ServiceStartMode)settings.StartType;
if (settings.DependedOn != null && settings.DependedOn.Length > 0)
{
this.serviceInstaller1.ServicesDependedOn = settings.DependedOn;
}
}
/// <summary>
/// 设计器支持所需的方法 - 不要
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
//
// ProjectInstaller
//
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller1,
this.serviceInstaller1});
}
public ServiceProcessInstaller ServiceProcessInstaller
{
get { return serviceProcessInstaller1; }
}
}
为了重用,可以把这些代码封装成DLL。新建一个类只需继承WindowServiceInstaller则可。这样,我们只需通过修改配置就可以实现你想要的程序名、描述...