Castle:Windsor Container入门级教程(翻译六)
原文连接:http://www.castleproject.org/container/gettingstarted/part1/index.html
来自官方的一个入门教程。写了一下简单的翻译。也作为是自己学习castle的记录吧。
IMHO: In My Humble Opinion 恕我直言。 这个缩写是这次翻译所学到的。^_^
在这个快速入门部分,将向你介绍一些Windsor Container的基础操作。你会惊奇:什么是Castle MicroKernel?可以说,当你在应用Windsor Container的时候你也在应用MicroKernel。
我们将用一个Winforms项目来试验Windsor container,跟随下面的步骤来建立它吧。
打开Visual Studio 从New\Project... 中选择 Windows Application
现在建立一个叫App的类。我们将会用它作为程序的入口。
namespace GettingStartedPart1
{
using System;
using System.Windows.Forms;
public class App
{
public static void
{
Application.Run(new Form1());
}
}
}
在Visual Studio中注释掉Form1.cs的 程序入口方法。
namespace GettingStartedPart1
{
using System;
using System.Windows.Forms;
public class Form1 : System.Windows.Forms.Form
{
...
// [STAThread]
// static void
// {
// Application.Run(new Form1());
// }
}
}
你可以从这里下载完整的示例:
我们假设你已经下载了Castle项目的组件到你的本地计算机上。如果你还没有,我们希望你去下载MSI installer distribution。Visual Studio可以使用这些组件。
添加引用下面的组件。
Castle.Core.dll
Castle.MicroKernel.dll
Castle.Windsor.dll
Castle.DynamicProxy.dll
如果你使用其他的开发环境或者通过Nant来编译的,确保上面所述的组件已经从Castle的安装目录中被引用。
继续下面的步骤,我们需要建立一个Windsor Container的实例并且在它里面注册组件。这将会令到Windsor Container对组件起作用。让我们开始在Windsor Container上注册Form1这个类。
using Castle.Windsor;
public class App
{
public static void
{
IWindsorContainer container = new WindsorContainer();
// Register the component
container.AddComponent("form.component", typeof(Form1));
// Request the component to use it
Form1 form = (Form1) container[typeof(Form1)];
// Use the component
Application.Run(form);
// Release it
container.Release(form);
}
}
你可以运行上面的程序并证明它如你所想那样正常工作。
现在建立一些虚拟的服务来模拟一个真正的应用程序。例如让我们建立一个HttpServiceWatcher.在真实的世界HttpServiceWatcher 将会不断地向http服务器发出请求,以确保服务器正在运行。
如果服务器没有运行,这个怎么办呢?OK,我们必须让它做一些事情。例如发送一个电子邮件给某个人,或者启动一个警报。甚至两件事情一起做。那么这个代码应该如何构造呢?
如果你的答案是,让HttpServiceWatcher增加发送电子邮件和发出警报的功能,那么你应该阅读更多关于关注点分离的资料。正如其名字所示,HttpServiceWatche应该只是检测Http服务器的运行状态。发送电子邮件或者发出警报的逻辑应该由不同的IFailureNotifier 服务来执行。
我们的服务应该如下所示:
namespace GettingStartedPart1
{
using System;
public class HttpServiceWatcher
{
public void StartWatching()
{
}
public void StopWatching()
{
}
}
}
跟着我们建立IfailureNotifier以及实现了这个接口的EmailFailureNotifier和AlarmFailureNotifier
namespace GettingStartedPart1
{
using System;
public interface IFailureNotifier
{
void Notify();
}
}
namespace GettingStartedPart1
{
using System;
public class EmailFailureNotifier : IFailureNotifier
{
public void Notify()
{
// Send email to admins
}
}
}
namespace GettingStartedPart1
{
using System;
public class AlarmFailureNotifier : IFailureNotifier
{
public void Notify()
{
// Turn on alarm
}
}
}
但是HttpServiceWatcher如何能获得与一个notifier的连接呢?我们可以用构造函数或者一个属性。问你自己下面的问题:
对于一个没有notifier的HttpServiceWatcher来说这有意义吗?
如果监测失败而且没有notifier,那么HttpServiceWatcher应该怎么做?
恕我直言,HttpServiceWatcher需要一个notifier (HttpServiceWatcher依赖于 IFailureNotifier 的实现)。让我们将这个结论清晰地体现在Windsor Container上
public class HttpServiceWatcher
{
private IFailureNotifier notifier;
public HttpServiceWatcher(IFailureNotifier notifier)
{
this.notifier = notifier;
}
public void StartWatching()
{
// should start a thread to ping the service
// if (pingresult == Failed)
// {
notifier.Notify();
// }
}
public void StopWatching()
{
// stop thread
}
}
现在Windsor Container(其实是MicroKernel)知道为了建立一个HttpServiceWatcher实例,他需要一个实现了IfailureNotifier的组件的支持。
修改App类来配置组件:
:
public static void
{
IWindsorContainer container = new WindsorContainer();
// Register the components
container.AddComponent("httpservicewatcher", typeof(HttpServiceWatcher));
container.AddComponent("email.notifier", typeof(IFailureNotifier), typeof(EmailFailureNotifier));
container.AddComponent("alarm.notifier", typeof(IFailureNotifier), typeof(AlarmFailureNotifier));
container.AddComponent("form.component", typeof(Form1));
// Request the component to use it
Form1 form = (Form1) container[typeof(Form1)];
...
我们应该让Form1来请求HttpServiceWatcher。这里有点要注意的,如果我们修改了由Visual Studio designer自动生成的构造函数,建立一个带参数的构造函数,那么Visual Studio designer 会抱怨的。所以我们只是建立另一个构造函数。
public class Form1 : System.Windows.Forms.Form
{
private readonly HttpServiceWatcher serviceWatcher;
private System.ComponentModel.Container components = null;
public Form1()
{
InitializeComponent();
}
public Form1(HttpServiceWatcher serviceWatcher) : this()
{
this.serviceWatcher = serviceWatcher;
}
...
现在你可以运行这个程序,调试和看看这个程序是怎么运作的。添加两个按钮到你的窗体中以方便你调用 从我们开始到现在你或者已经产生如下的一些问题:
HttpServiceWatcher获得了哪个IfailureNotifier的实例?我怎么修改呢?
如果我想让HttpServiceWatcher得到一系列的IfailureNotifier应该怎么做呢?
我怎么配置HttpServiceWatcher来接收参数呢?例如增加一个URL.
这些问题都 很好,默认的Windsor Container只是支持第一个服务的注册。所以HttpServiceWatcher只是获得了一个EmailFailureNotifier的实例。我们可以重写服务来修改它。
你也可以传递一系列的notifiers,但是你需要通知Windsor Container那些实例是你想传递的。假设你有10个IfailureNotifier的实例。你必须通知Windsor Container那些是你想要的。简而言之更多的实例也是同样的道理。
最后,你可以提供一个URL给HttpServiceWatcher,更可以给EmailFailureNotifier 一个邮件列表。我们将会看到如何来完成上面这些事情。
外部配置Windsor Container
到目前为止我们已经用代码配置了Windsor Container。现在让我们的配置脱离具体代码,以便得到更好的适应性,以及我们可以修改它而不需要重新编译应用程序。
配置是非常小的,而且默认是一个XML文件。我们可以用一个标准的XML文件或者利用AppDomain的配置来辅助。现在我们使用后者。
添加一个App.config文件到你的Visual Studio项目中。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>
Visual Studio将会维护好你的可以执行文件集的复制或者重命名。例如:
GettingStartedPart1.exe.config
现在添加一个节点来配置Windsor Container
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="castle"
type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<castle>
<components>
</components>
</castle>
</configuration>
现在我们将配置从App.cs文件转移到App.config中的"castle"节点上。如下所示:
<castle>
<components>
<component
id="httpservicewatcher"
type="GettingStartedPart1.HttpServiceWatcher, GettingStartedPart1" />
<component
id="email.notifier"
service="GettingStartedPart1.IFailureNotifier, GettingStartedPart1"
type="GettingStartedPart1.EmailFailureNotifier, GettingStartedPart1" />
<component
id="alarm.notifier"
service="GettingStartedPart1.IFailureNotifier, GettingStartedPart1"
type="GettingStartedPart1.AlarmFailureNotifier, GettingStartedPart1" />
<component
id="form.component"
type="GettingStartedPart1.Form1, GettingStartedPart1" />
</components>
</castle>
最后,我们需要通过XmlInterpreter和配置资源建立一个Windsor Container。
using Castle.Core.Resource;
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
public class App
{
public static void
{
IWindsorContainer container =
new WindsorContainer(
new XmlInterpreter(new ConfigResource("castle")));
// Request the component to use it
Form1 form = (Form1) container[typeof(Form1)];
// Use the component
Application.Run(form);
// Release it
container.Release(form);
}
}
测试你的工作,应该会如你所愿地运作的。
传递配置参数
让我们改进HttpServiceWatcher另到他可以接收一个URL,也就是它所请求的URL了。首先这个URL参数是必须的还是可选的呢?我们先假设它是可选的。,所以我们需要添加一个属性
public class HttpServiceWatcher
{
private IFailureNotifier notifier;
private string url = "default url";
public HttpServiceWatcher(IFailureNotifier notifier)
{
this.notifier = notifier;
}
public string Url
{
get { return url; }
set { url = value; }
}
...
怎么在配置文件中配置这个参数呢?很简单:使用parameters节点
<component
id="httpservicewatcher"
type="GettingStartedPart1.HttpServiceWatcher, GettingStartedPart1">
<parameters>
<Url>different url</Url>
</parameters>
</component>
每一个由parameters节点关闭的节点都应该在一个属性或者一个构造函数参数之后被命名
选择notifier
在开始之前,这里有两个notifiers但是HttpServiceWatcher只需要一个。它会要哪个呢?默认的就是第一个被注册的组件,也就是EmailFailureNotifier。但是如何你想改变一下,你应该怎样做 呢?
我们需要重写一个服务。那意味着什么呢?一个服务的重写代表在分析依赖的过程中配置入口会改变MicroKernel的行为。最后我们需要修改配置中传递一个不同的服务的构造参数。
public HttpServiceWatcher(IFailureNotifier notifier)
{
this.notifier = notifier;
}
<component
id="httpservicewatcher"
type="GettingStartedPart1.HttpServiceWatcher, GettingStartedPart1">
<parameters>
<notifier>${alarm.notifier}</notifier>
<Url>different url</Url>
</parameters>
</component>
${}就是服务所查找调用的
传递一系列的notifiers给HttpServiceWatcher
假设你不满意HttpServiceWatcher只是接收一个notifier的实例。好的,那么我们就让它接收一个notifiers数组
public class HttpServiceWatcher
{
private IFailureNotifier[] notifiers;
private string url = "default url";
public HttpServiceWatcher(IFailureNotifier[] notifiers)
{
this.notifiers = notifiers;
}
...
在我们的配置中,我们需要做一些修改
<component
id="httpservicewatcher"
type="GettingStartedPart1.HttpServiceWatcher, GettingStartedPart1">
<parameters>
<notifiers>
<array>
<item>${email.notifier}</item>
<item>${alarm.notifier}</item>
</array>
</notifiers>
<Url>different url</Url>
</parameters>
</component>
我们只是看到了关于Castle MicroKernel 和 Windsor Container 很少的一部分应用。你可以查阅开发文档来进一步了解更多的信息。