Windsor是Castle 的一個IOC容器。它構建於MicroKernel之上,功能非常之強大,能檢測類並了解使用這些類時需要什麼參數,檢測類型和類型之間工作依賴性,並提供服務或者發生錯誤時提供預警的機制。
通常IOC實現的步驟為-->建立容器-->加入組件-->獲取組件-->使用組件.
1.建立容器
建立容器也就是IWindsorContainer.接著我門要向容器中注冊服務,並告訴容器所注冊的服務由那一個類來實現他.通常建立容器我們可以用以下定義來實現:
1IWindsorContainer container = new WindsorContainer();
2.加入組件
向建立好的容器裡加入組件,直接調用容器的AddComponent()來完成.比如現在有一個寫日志的接口ILog,實現這個服務的組件是TextLog,那我門可以通過如下方法把該組件加入到容器:
1container.AddComponent("txtLog", typeof(ILog), typeof(TextLog));
3.獲取組件
獲取組件可以直接通過加入組件的時候使用的key來獲取,返回的是一個IWindsorContainer,這裡需要一個強制轉換.
1ILog log = (ILog)container["txtLog"];
4.使用組件
1//把當前時間寫入到日志文件去
2log.Write(DateTime.Now.ToShortDateString()); 上面就是一個IOC容器的工作過程,從創建容器--加入組件--獲取組件--使用組件.下面我看來看看一個小實例,也就是我在學習IOC的時候結合網上的資源自己小試牛刀瞎寫的.
-------------------------------------------------------------------------------------------------------------
ILog接口(服務)的定義:
1using System; 2using System.Collections.Generic; 3using System.Text; 4 5namespace IOCDayOne 6{ 7 /**//// <summary> 8 /// 日志服務 9 /// </summary> 10 public interface ILog 11 { 12 /**//// <summary> 13 /// 寫日志方法 14 /// </summary> 15 /// <param name="msgStr">日志內容</param> 16 void Write(string msgStr); 17 } 18} 19
TextLog組件的定義:
1namespace IOCDayOne 2{ 3 /**//// <summary> 4 /// ILog服務的組件 5 /// </summary> 6 public class TextFileLog:ILog 7 { 8 private string _target; //私有成員 9 private ILogFormat _format; //ILogFormat一內聚的方式存在 10 11 /**//// <summary> 12 /// 構造方法 13 /// </summary> 14 /// <param name="target">標識</param> 15 /// <param name="format">提供格式化服務的接口</param> 16 public TextFileLog(string target, ILogFormat format) 17 { 18 this._target = target; 19 this._format = format; 20 } 21 22 /**//// <summary> 23 /// 寫日志的實現方法 24 /// </summary> 25 /// <param name="msgStr">日志內容</param> 26 public void Write(string msgStr) 27 { 28 string str = _format.Format(msgStr); //格式化日志 29 str += _target; //日志內容為格式化後的字符+類構造時傳入的標識參數 30 31 //下面將日志記錄到文本文件 32 FileStream fs = new FileStream(this._target, FileMode.Append); 33 StreamWriter sw = new StreamWriter(fs, Encoding.Default); 34 sw.WriteLine("Log:-->" + str); 35 sw.Close(); 36 } 37 } 38}
XML配置文件的定義(指定將日志記錄到C:\Log.txt),TextLog組件需要存儲路徑的參數,我們在建立IOC容器的時候指定容器到這個配置文件中來找"target":
1<?xml version="1.0" encoding="utf-8" ?> 2<configuration> 3 <components> 4 <component id="txtLog"> 5 <parameters> 6 <target>C:\Log.txt</target> 7 </parameters> 8 </component> 9 </components> 10</configuration> 11
出此之外還有一個格式化日志的服務IlogFormat,可將日志格式化為一定的格式輸出,定義如下:
1namespace IOCDayOne 2{ 3 /**//// <summary> 4 /// 格式化日志服務接口 5 /// </summary> 6 public interface ILogFormat 7 { 8 /**//// <summary> 9 /// 格式化日志方法 10 /// </summary> 11 /// <param name="msgStr">日志內容</param> 12 /// <returns></returns> 13 string Format(string msgStr); 14 } 15}
實現ILogFormat服務的組件定義為:
1namespace IOCDayOne 2{ 3 public class TextFormat:ILogFormat 4 { 5 /**//// <summary> 6 /// 格式化日志內容 7 /// </summary> 8 /// <param name="msgStr">日志內容</param> 9 /// <returns></returns> 10 public string Format(string msgStr) 11 { 12 return "On:" + msgStr; 13 } 14 } 15}
到這裡,來寫個測試方法測試看看.
1namespace IOCDayOne 2{ 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //建立容器 8 IWindsorContainer container = new WindsorContainer(new XmlInterpreter("http://www.cnblogs.com/Config/ConfigBase.xml")); 9 //加入組件 10 container.AddComponent("txtLog", typeof(ILog), typeof(TextFileLog)); 11 container.AddComponent("format", typeof(ILogFormat), typeof(TextFormat)); 12 //獲取組件 13 ILog log = (ILog)container["txtLog"]; 14 //使用組件 15 log.Write(DateTime.Now.ToShortDateString()); 16 } 17 } 18}
測試輸出的結果為:
Log:-->On:2008-4-3C:\Log.txt
上面的main()中可以看書,在使用組件的時候只傳遞了一個參數(日志內容),而實現ILog服務的組件的構造方法是需要兩個參數,
1/**//// <summary> 2/// 構造方法 3/// </summary> 4/// <param name="target">標識</param> 5/// <param name="format">提供格式化服務的接口</param> 6public TextFileLog(string target, ILogFormat format) 7{ 8 this._target = target; 9 this._format = format; 10}
在前面向容器中注冊ILog服務的時候,告訴容器TextFileLog實現了這個服務,這裡還設置了一個key的參數,後面可以通過這個參數來獲取這個服務,注冊ILog時容器會發現這個服務依賴於其他的服務,它會自動去尋找,如果找不到這樣的服務,則會拋出一個異常.
到這裡,一個IOC的完整實例就完成了.其實還有另外一種方式實現.詳細見下面.
-------------------------------------------------------------------------------------------------------------
上面是通過把配置寫到XML的,而組件與服務是直接通過容器的加入組件來完成匹配.這樣顯然是不夠靈活的,一單需求發生了變化,實現ILog服務的組件不在是TextFileLog的時候又該怎麼處理呢?我們又去修改加入組件時的程序代碼來實現,這樣是可以達到需求的,但是這樣做很明顯不夠靈活.那怎麼做才能讓服務去調用具體的實現組件修改方便呢?另一種方式是通過配置文件(App.config/Web.config)來實現.
下面是針對上面這個實例定義的App.config配置:
1<?xml version="1.0" encoding="utf-8" ?> 2<configuration> 3 <configSections> 4 <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler,Castle.Windsor"/> 5 </configSections> 6 <castle> 7 <components> 8 <component id="txtLog" service="IOCDayOne.ILog,IOCDayOne" type="IOCDayOne.TextFileLog,IOCDayOne"> 9 <parameters> 10 <target>C:\Log.txt</target> 11 </parameters> 12 </component> 13 <component id="format" service="IOCDayOne.ILogFormat,IOCDayOne" type="IOCDayOne.TextFormat,IOCDayOne"> 14 <paramters> 15 <target>DayOne</target> 16 </paramters> 17 </component> 18 </components> 19 </castle> 20</configuration>
這時,測試方法就需要改動下了,通過配置文件來完成IOC,詳細如下:
1namespace IOCDayOne
2{
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 //建立容器,並通過配置文件最動加入組件
8 IKernel kernel;
9 Castle.Core.Resource.ConfigResource source = new Castle.Core.Resource.ConfigResource();
10 XmlInterpreter interpreter = new XmlInterpreter(source);
11 WindsorContainer windsor = new WindsorContainer(interpreter);
12 kernel = windsor.Kernel;
13
14 //獲取組件
15 ILog log = (ILog)kernel["txtLog"];
16
17 //使用組件
18 log.Write(DateTime.Now.ToShortDateString());
19 }
20 }
21}
今天的IOC就學與此,筆記也記於此.小弟是剛開始著手學習這門技術,望園裡前輩別見笑,我不趕搬門弄虎的寫什麼文章,這篇文章只是我的一篇學習筆記罷了.
本文配套源碼