應用框架的設計與實現——.NET平臺(8.3 源碼分析)

本章的目的是實現一個 Windows服務 的通用框架程序,使用該框架,windows服務開發者不需瞭解開發 windows服務的細節,
只需實現IService接口,將編譯生成的dll文件名、服務類全路徑名寫在配置文件內,就可以實現windows服務功能的加載和啓動。

1.IService

public interface IService
{
    
void Start();    // windows 服務啓動時會以線程的方式調用這個方法;需要實現什麼功能就寫這裏吧
    void Stop();    // windows 服務關閉時會調用這個方法;有什麼需要釋放的資源,保存的數據就在這裏寫吧
    void Initialize(XmlNode configXml);    // 對象初始化的方法,在Start()方法前執行,參數是定義在配置文件中的xml節點
}



2.配置文件

<configuration>
    
<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

// 繼承自ServiceBase才能被windows識別爲windows服務的實現
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>
/// 用來切換運行用戶身份的類
/// </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;
        }

    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章