Windsor 是 Castle 專案的核心 IoC (Inversion of Control) 容器,建構於 MicroKernel 之上。它能自動檢測類別相依性、解析建構函式參數、管理物件生命週期,並提供服務定位與攔截(AOP)等進階功能。
IWindsorContainer container = new WindsorContainer();container.AddComponent("key", typeof(IService), typeof(Impl));ILog log = (ILog)container["key"];public interface ILog
{
void Write(string msgStr);
}
public interface ILogFormat
{
string Format(string msgStr);
}
public class TextFileLog : ILog
{
private readonly string _target;
private readonly ILogFormat _format;
public TextFileLog(string target, ILogFormat format)
{
_target = target;
_format = format;
}
public void Write(string msgStr)
{
string str = _format.Format(msgStr) + _target;
using (var fs = new FileStream(_target, FileMode.Append))
using (var sw = new StreamWriter(fs, Encoding.Default))
sw.WriteLine("Log:-->" + str);
}
}
public class TextFormat : ILogFormat
{
public string Format(string msgStr) => "On:" + msgStr;
}
<configuration>
<configSections>
<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
<component id="txtLog" service="IOCDayOne.ILog,IOCDayOne" type="IOCDayOne.TextFileLog,IOCDayOne">
<parameters>
<target>C:\Log.txt</target>
</parameters>
</component>
<component id="format" service="IOCDayOne.ILogFormat,IOCDayOne" type="IOCDayOne.TextFormat,IOCDayOne" />
</components>
</castle>
</configuration>
class Program
{
static void Main(string[] args)
{
// 透過 XML 組態建立容器
IKernel kernel;
var source = new Castle.Core.Resource.ConfigResource();
var interpreter = new XmlInterpreter(source);
var windsor = new WindsorContainer(interpreter);
kernel = windsor.Kernel;
// 解析並使用
ILog log = (ILog)kernel["txtLog"];
log.Write(DateTime.Now.ToShortDateString());
}
}
輸出:Log:-->On:2008-4-3C:\Log.txt
TextFileLog 建構函式需要 string target 與 ILogFormat format。容器在註冊 ILog 時發現相依 ILogFormat,會自動從容器尋找已註冊的 format 組件注入。若找不到則拋出例外。
上例仍在程式碼呼叫 AddComponent。若需求變更(如換成 DatabaseLog),修改程式碼違反 OCP。解法:將所有註冊移至 App.config:
<castle>
<components>
<component id="txtLog" service="IOCDayOne.ILog,IOCDayOne" type="IOCDayOne.TextFileLog,IOCDayOne">
<parameters><target>C:\Log.txt</target></parameters>
</component>
<component id="format" service="IOCDayOne.ILogFormat,IOCDayOne" type="IOCDayOne.TextFormat,IOCDayOne" />
</components>
</castle>
啟動碼簡化為:
var windsor = new WindsorContainer(new XmlInterpreter(new ConfigResource()));
ILog log = (ILog)windsor.Kernel["txtLog"];
log.Write(DateTime.Now.ToShortDateString());
此時更換實作只需改組態檔,達成**依賴倒置**與**開放封閉原則**。
下一篇將示範如何在真實專案中封裝容器單例、整合到 ASP.NET WebForm / MVC 生命週期中。