Share via


每周源代码24-扩展版-.NET插件、提供商、属性、加载项和模块

[原文发表地址]The Weekly Source Code 24 - Extensibility Edition - PlugIns, Providers, Attributes, AddIns and Modules in .NET

[原文发表时间]2008-04-18 01:43

我对开发人员们怎么运用插件和其他方法来扩展应用程序越来越感兴趣了。亲爱的读者,请大家看看我正在进行的最新的通过阅读源代码使自己成为一个更好的开发者的博客。亲爱的读者,我现在向你们展示“每周源代码”系列中的第24篇。

“扩展”一个应用程序或framework有很多方法。或许有许多种模式。你可以参见Gang of Four Patterns using C# over here.来了解运用C#D的四种模式。

我这周一直在查看可扩展的或已经扩展的三大块代码。首先是xUnit.NET,代码块上的新单元测试框架(直到最后我尝试了文件/新建项目,然后蹦出了"HanselTest2000"),第二个是2008年3月份,Miguel Castro在一个题为Sexy Extensibility Patterns的CINNUG会议上发布的源码。Miguel用该模式创建了名为CodeBreeze的代码生成/数据映射工具。前不久在DNRTV上展示过。第三个是Windows Live WriterWLW SDK的插件设计。

本博客并非试图给出一张完整的列表,只是里面有很多很酷的代码,这让我对扩展一些东西很感兴趣。我很喜欢这三个范例,因为每个范例都有一个以上的扩展方法。

扩展软件其实就是添加一些未启动的功能。有很多方法可以做到。例如,添加一个类似VBA或者PowerShell或托管脚本的脚本引擎将是途径之一。如要创建一个公共脚本-API将是对这个主题的转折点。主机通过基类派、实现借口或源代码事件添加加载项或插件。使用System.AddIn,也是个办法。使用依赖注入容器,是扩展应用程序的一个更先进更有效的途径。

xUnit.NET
xUnit.NETBrad WilsonJim Newkirk(以前以NUnit闻名)创建的单位测试框架。开发人员们对其框架的初步反应是一个大大的疑问:“说真的,我们真的需要另一个测试框架么?”但他们还是迎难而上,正如小模型框架一样,他们开始获得应得的尊重。它有一个MSBuild任务,Resharper和TestDriven.NET测试试验支持,更重要的是,该框架有些有趣的扩展点。

xUnit.NET源代码是非常整洁的。这真的是句恭维话。就像你到别人家做客,你在问:“装饰设计师是谁?“的同时意识到该房间如此干净,井井有条。

顺便说一句:在Visual Studio中使用“解决方案文件夹”的人并不多。说真的,伙计们,只需单击右键,然后“添加 / 新的解决方案文件夹,”,开始拖动周围的文件,立马就整洁了。

他们将一些有争议的地静态扩展方法分成单独的项目,包括NET 3.5-特定功能的xunitext和xunitext35。所以,对于框架“下行”的开发人员来说,该扩展方法无疑是一个粗糙的扩展点。

他们将属性作为扩展框架的主要途径。例如,如果你想知道测试前后的情况。

clip_image002

从BeforeAfterTest属性上导出一个新属性,然后对其进行测试。[Fact]属性是标准属性。他们用它来取代[Test]:

clip_image004

现在,Before()和After()的代码将执行此次测试。

如果你有自己的测试框架,但你想使用xUnit.NET。这是你可以看到[RunWith]属性,你可以自行测试,例如,你可以下指令如"run this test with nUnit."。可以通过两种方法来使用,可以输入[RunWith(typeof(MyRunner)]或者使用自定义属性,如:

clip_image006

nUnitCommand实现了一个非常清晰的ITestCommand接口,“描述了在测试类中执行所有测试的能力。”

clip_image008

我觉得这是个非常简单有效的接口。该框架“吃自家的饭”,意思是,xUnit.NET的开发者们适当地考虑了应该考虑的因素,并使用了自己的扩展点。如果你有个很棒的框架,那么使用自己的框架来构建东西是唯一且最好的途径,可以帮助你找出没有运行的东西。

NUnitCommand执行后,再使用NUnit SDK/API运行测试。如果你愿意,可以移到xUnit.NET,每次向Nunit或另一个测试靠近一点,在同一个运行器下运行所有测试。

另一个扩展代码的途径是使用现有的知名接口如IComparer<T>。这是个测试框架,所以有很多Asserts语句,如Assert.Equal和Assert.Contains。Assert.InRange有一个重载,如下所示,然后你可以将Icomparer作为一个可选参数。

clip_image010朗读

对有些人来说,是很明显的。但是它是深思熟虑的明显而又清晰的可扩展点。深思熟虑的明显性说起来容易,做起来难。我觉得,MoqxUnit.NET是形影不离的。他们的合作是如此的天衣无缝,且各自都有类似的目标。

性感的扩展模式

有些人很喜欢写代码的工作。他们将这种模式描述成“性感”,而非“帅气”或“时髦”。Miguel在CINNUG网站上发布了他的幻灯片版面以及用C#和VB写的代码。

Miguel在他的演示中总结了三个主要的可扩展类型:

供应商 - 允许数据和行为的抽象
插件-添加新的行为
模块 - 集中插件功能和执行管理的标准

提供商基于像这样的策略设计模式。你会在ASP.NET 2.0上看到类似的东西。控制器或上下文类需要一个方式(因此,运用“战略”办事)。传统的提供所需战略的实例已经传入,但现在,它可能来自IOC框架或一个配置文件。

他们通常很简单且很容易编写。设置一个提供数据的接口如下:

clip_image011

然后使用它。这是个非常简单的示例。但它通常会被积压在隐藏配置文件和激活的ProviderFactory中,或者会拥有一个新的示例:

clip_image013

顺便说一下: 我个人觉得,在Miguel原来以令人倒胃口的准匈牙利命名。我非常了解他才这样说J

因此,供应商提供了插件添加功能等,如:

clip_image015

您可能将一大堆插件添加到了您的配置文件中,然后进行同步访问。在此例中,或许是提供商的一个后处理步骤:

clip_image017

据Miguel的说法,模块局就像参与在各个步骤和许多点(如HttpModules)和改变功能的过滤器一样。首先,你可以定义一些事件:

clip_image019

您可以添加一些模块到您的应用程序中,让他们遵从三个或多个“事件”。然后,你需要问问自己,这些东西是否按序排列,更重要的是,一个模块可否取消进程?要做到这一点,模块必须有意识地遵从取消布尔值,但这也并不需强制执行的。

在这个示例中,一个模块被传入到了ModuleEvents中,这样它们就可以连接到共享委派。这就是所谓的多番委托。因为如果我这样访问它的话,每个人都可以这么访问:

clip_image021

您可以这样访问:

clip_image023

或者,您可以自旋这些委派,并激活它们。检查取消标志,然后自己停止这一切。Miguel开发了一个很棒的示例应用程序以及阐释说明的写着许多代码的PPT。

然后你可以对所有的概念进行整合,把它们编入一个单独的带有提供商,插件,和模块一同运行的可扩展的应用程序中。我喜欢将所有的接口单独地放在另一个程序集中,只有当合同变更时才再慢慢地更换以个版本。

Windows Live Writer

我以前用Windows Live Writer写博客。此时此刻我还在使用它。如果您使用的是管理员的网页来发布你的博客,那么你可以停止使用了,在这个网址下载吧Go download it now,我就在这儿等着。它有3种可扩展性:(来源于MSDN):

API的应用,通过发布Writer 来发新帖子或链接,字符段,图像,馈料源的"Blog This"项目
内容来源插件API,为Writer的功能扩展,插入,编辑,和发布新的内容类型。
提供商定制的API,定制Writer的能力,以及为用户界面添加新的功能。

让我们来处理最后一个难题。首先,提供商订制API。可扩展性也意味着在完全不使用代码的情况下扩展应用程序。可参加to extend the Windows Live Writer UI using only an XML file for DasBlog。不需要用到代码。有时候,一个周全的XML文件就提供满足你需要的扩展点。

内容源插件API华而不实,你可以自接添加“插入”命令到WLW。此时此刻,在照片库中有85个插件。

去年的这个时候,我在Travis's CueCat上创建了一个CueCat Windows Live Writer插件。这使得我可以更快速地发布我的Monthly Reading List帖子(杯具的是,终以懒惰而告终。本来是每月一次,最后变成每年一次,提醒自己:一定要每个月发布一个阅读清单)

不管怎么说,我写了篇关于Coding4Fun的文章,并把它发布到了玻壳上。该插件如下所示:

clip_image025

Windows Live Writer有一个很酷的插件模型。有能添加很多功能的潜力。您需要田间链接和图片到用户界面,一些未定义的形式。然后,你要进行存储,并把HTML插入到主要的编辑窗口中。这可能是一个复杂的插件类型,但是Joe Cheng和他的开发团队成功地开发了它。依我个人浅见,确实非常容易。

WLW的插件模型是怎样做到的呢?下列代码充分充分说明了该方法:

clip_image027

该插件模型结合了很多元素。类的属性详细地介绍了图像(作为资源嵌入),文本,URL和独特的GUID的位置。基类可以使"Hello World"插件变成一行事件。展示任意WinForm的方法很清晰,展示完后再告知WLW结果。HTML通过新的内容引用返回。而返回值是一个标准的DialogResult。如果您需要存储状态,他们会在初始化阶段传递一个简单的类似字典的界面到你的插件中。作为一个插件,你无需赶紧存储或是出现在插件列表中。你只需专注于主对话框。

你有优雅、酷、方便和巧妙扩展机制的好示例么?