只需實現IService接口,將編譯生成的dll文件名、服務類全路徑名寫在配置文件內,就可以實現windows服務功能的加載和啓動。
1.IService
{
void Start(); // windows 服務啓動時會以線程的方式調用這個方法;需要實現什麼功能就寫這裏吧
void Stop(); // windows 服務關閉時會調用這個方法;有什麼需要釋放的資源,保存的數據就在這裏寫吧
void Initialize(XmlNode configXml); // 對象初始化的方法,在Start()方法前執行,參數是定義在配置文件中的xml節點
}
2.配置文件
<configSections>
<section name="Framework" type="SAF.Configuration.ConfigurationHandler,SAF.Configuration" />
<section name="MyApplication" type="SAF.Configuration.ConfigurationHandler,SAF.Configuration" />
</configSections>
<Framework type="SAF.Configuration.ConfigurationManager,SAF.Configuration">
<!-- windows服務 的配置節點 -->
<SAF.WindowsService>
<!-- 一個 windows服務 的例子 -->
<Service name="empty" type="SAF.WindowsService.EmptyService,SAF.WindowsService">
<!-- 用戶可自行定義的節點(1個或者多個) -->
<File>C: empEmptyService.txt</File>
<!-- 運行用戶的配置信息 -->
<RunAs InheritIdentity="false">
<Domain>AVANADE-C006T6X</Domain>
<User>user1</User>
<Password>password</Password>
</RunAs>
</Service>
</SAF.WindowsService>
</Framework>
</configuration>
3.Windows服務通用框架程序
這一部分主要有3個類:
Service1:windows服務通用框架類;
SecuritySwitchThread:單個服務組建的用戶賬號切換類;
ProjectInstaller:vs.net生成的,用來安裝 windows服務的類。
Service1
public class Service1 : System.ServiceProcess.ServiceBase
{
/// <summary>
/// Required designer variable.
/// </summary>
private ArrayList threadArray = new ArrayList(); // 單個windows服務所在的線程池
private ArrayList instanceArray = new ArrayList(); // windows服務對象池
private System.ComponentModel.Container components = null;
public Service1()
{
InitializeComponent();
}
// vs.net自動生成的代碼
// 進程中可以運行的用戶服務是Service1,可以添加其它的
static void Main()
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service1() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.ServiceName = "SAF.WindowsService";
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
/// <summary>
/// windows服務啓動時要執行的方法
/// </summary>
protected override void OnStart(string[] args)
{
// 取得配置文件中windows服務節點的信息
ConfigurationManager cm = (ConfigurationManager)ConfigurationSettings.GetConfig("Framework");
SAF.Configuration.ServiceConfiguration serviceConfig = cm.ServiceConfig;
XmlNode servicesXml = serviceConfig.ServicesXml;
// 遍歷windows服務節點的子節點
foreach (XmlNode node in servicesXml.ChildNodes)
{
try
{
string typeInfo;
// 建立windows服務對象
typeInfo =node.Attributes["type"].Value;
Type type = Type.GetType(typeInfo);
IService instance = (IService)Activator.CreateInstance(type);
// 初始化windows服務對象
instance.Initialize(node);
XmlNode runAs = node.SelectSingleNode("RunAs");
instanceArray.Add(instance);
// 使用SecuritySwitchThread 對象處理windows服務對象
ThreadStart ts = new ThreadStart(instance.Start);
SecuritySwitchThread sst = new SecuritySwitchThread(ts,runAs);
// windows服務開始執行
sst.Start();
threadArray.Add(sst.BaseThread);
}
catch (Exception ex)
{
//write to the event log
}
}
}
/// <summary>
/// delegate used when invoke the OnStop method asynchronous during service shut down.
/// </summary>
public delegate void OnStopDelegate();
/// <summary>
/// windows服務停止時要執行的方法
/// </summary>
protected override void OnStop()
{
foreach (object o in instanceArray)
{
try
{
IService service = (IService)o;
if (service !=null)
{
//invoke the delegate asynchronous to stop each started service.
OnStopDelegate osd = new OnStopDelegate(service.Stop);
osd.BeginInvoke(null,null); // 異步方式通知服務類結束運行
}
}
catch (Exception ex)
{
//write to the event log
}
}
// 給出5秒鐘的時間,等待服務完成結束操作
Thread.Sleep(5000);
foreach (object o in threadArray)
{
try
{
Thread t = (Thread)o;
if (t !=null)
{
// 如果線程還在運行狀態,那麼強制結束它
if (t.IsAlive == true)
{
t.Abort();
}
}
}
catch (Exception ex)
{
//write to the event log
}
}
}
}
SecuritySwitchThread
/// 用來切換運行用戶身份的類
/// </summary>
public class SecuritySwitchThread
{
private ThreadStart serviceDelegate;
private XmlNode runAs;
private Thread newT;
/// <summary>
/// 接受一個委託和一個xml節點作爲參數
/// </summary>
/// <param name="start">the ThreadStart delegate for the target method</param>
/// <param name="xml">the configuraiton data contains the user account information</param>
public SecuritySwitchThread (ThreadStart start, XmlNode xml)
{
serviceDelegate = start;
runAs = xml;
// create a new thread that calls the WrappingMethod
newT = new Thread(new ThreadStart(WrappingMethod));
}
public void Start()
{
newT.Start();
}
/// <summary>
/// 包裝後的方法
/// </summary>
private void WrappingMethod()
{
// 切換當前使用的用戶賬號
bool inheritIdentity = Boolean.Parse(runAs.Attributes["InheritIdentity"].Value);
if (inheritIdentity == false)
{
string userid = runAs.SelectSingleNode("User").InnerText;
string password= runAs.SelectSingleNode("Password").InnerText;
string domain = runAs.SelectSingleNode("Domain").InnerText;
//call the utility class to switch the current thread's security context.
SecurityUtility su = new SecurityUtility(); // SAF.Utility.SecurityUtility 前面提到過的切換用戶的方法
su.Switch(userid, password,domain);
}
// 實際開始執行線程
serviceDelegate();
}
/// <summary>
/// 實際在運行的線程對象
/// </summary>
public Thread BaseThread
{
get
{
return newT;
}
}
}