本章我们将深入Nancy的内部,对Nancy的内部组件进行修改和调整。
那什么是bootstrap哪?字典里是这么介绍的:
一般而言,处于引导中(bootstrapping)是在终端用户可以使用之前开启软件或硬件的一种状态。 对于Nancy而言,引导过程(bootstrap)是应用程序刚刚开始启动到准备好应对服务请求这个过程中的发生的一连串事件。
一个自定义引导程序bootstrapper是开发人员自己定义的一个类,可以在应用开启时由Nancy的内核处理程序执行一些自定义选项或是过程。
这就好比好比买了辆二手汽车,然后调整发动机增加更多性能,添加一些内饰和新的收音机,根据自己的风格改进一些其他什么的。通过编写和使用自定义引导程序,就能给Nancy增加很多开箱即用的额外功能。
Nancy中采用引导程序(bootstrapper)主要有两方面的用途。首先是以方法的形式展现 钩子程序,配置选项以及其他用户级别的东西,开发人员可进行重载。其次是处理一些特定的任务,比如配置内置的Ioc容器(控制反转):TinyIOC ,提供对自己程序集的注册。
Ioc容器
在我们继续探索前,我想先介绍下Nancy的隐含特征:内置Ioc容器。
对于那些还不了解Ioc的读者先简单介绍下概念。IoC(Inversion of Control,控制反转)也称为依赖注入(Dependency Injection),是一种设计对象之间依赖关系的原则及其相关技术。当一个对象创建时,它所依赖的对象由外部传递给它,而非自己去创建所依赖的对象(比如通过new操作)。因此,也可以说在对象如何获取它的依赖对象这件事情上,控制权反转了。这种技术无外乎都是为了让软件更加高内聚低耦合。
对于基于Nancy的应用,Ioc容器也是用于自动装载依赖项。试看下面的路由模块:
using System;
using System.Collections.Generic;
using System.IO;
using Nancy;
using Nancy.Responses;
namespace nancybook.modules
{
public class BaseRoutes : NancyModule
{
private FakeDatabase _db;
public BaseRoutes()
{
Get[@"/"] = _ =>
{
var _db = new FakeDatabase();
var myList = db.GetHashCode();
return View["myview", myList];
};
}
}
}
这个例子很简单,但很有说明意义。
在这个模块中,FakeDatabase 是一个具体的依赖类(被引用的类)。这个比较难以管理,非常难以改变。试想你有20个这样的模块类,每个都定义了10条左右的URL,每个URL路由中都引用同样的数据访问库,每次使用时都需要创建一个新的实例。
假如你现在需要把FakeDatabase 修改为RealDatabase。然后你会突然意识这会涉及到多少工作量。
使用Ioc容器在这方面就能提升很多。如下:
using System;
using System.Collections.Generic;
using System.IO;
using Nancy;
using Nancy.Responses;
namespace nancybook.modules
{
public class BaseRoutes : NancyModule
{
private readonly FakeDatabase _db;
public BaseRoutes(FakeDatabase db)
{
_db = db;
Get[@"/"] = _ =>
{
var myList = _db.GetHashCode();
return View["myview", myList];
};
}
}
}
这个例子和之前的差不多,只是使用了Ioc容器来管理数据访问库。一个路由模块即使使用10次数据访问类,也只需要修改两个地方:一个是私有变量,另外是构造函数的参数。
Ioc容器会处理其他部分,包括在使用数据库访问类前,就给_db 装载正确的引用实例。
还有更好处理办法, 在Nancy的 bootstrapper类中,通过重载Ioc容器的默认设置,告诉Nancy在需要使用FakeDatabase对象时,使用RealDatabase对象进行替换。这样仅仅通过一个全局类中的修改,节省了每个路由模块中的两处修改。
Nancy可以使用很多种的Ioc容器,你可以通过NuGet来进行启用。如果你从来还接触过Ioc容器,也喜欢这种工作方式的话,内置的Ioc容器已经足够。
让我们把关注拉回到Bootstrapper类吧。
默认bootstrapper
关于重载和自定义类的讨论可能让你觉得实现这么一个Nancy bootstrapper需要大量的工作,也许是不值得的。
当然如果让你从零开始写这么一个类确实如此。然而Nancy的开发团队已经想到前头,为你提供了一个叫做DefaultNancyBootStrapper的类。
你得到一个自定义bootstrap类只需要简单继承下即可:
using System.Text;
using Nancy;
using Nancy.Bootstrapper;
namespace nancybook
{
public class CustomBootstrapper : DefaultNancyBootstrapper
{
}
}
在类主体中,你可以通过重载方法来加载自定义的功能实现方法。举个例子,你有一些外部数据库问代码库,其中使用到了泛型编程(方便共用相同的方法)。采用接口形式来定义基类,在不同的子类中实现具体功能,然后告诉Ioc容器去装载:
using System.Text;
using demodata;
using demodata.entities;
using Nancy;
using Nancy.Authentication.Forms;
using Nancy.Bootstrapper;
using Nancy.Conventions;
using Nancy.Session;
using Nancy.TinyIoc; namespace nancybook
{
public class CustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureApplicationContainer(TinyIoCContainer
container)
{
base.ConfigureApplicationContainer(container);
container.Register<IDataProvider<Genre>>(new GenreDataProvider());
container.Register<IDataProvider<Album>>(new AlbumDataProvider());
container.Register<IDataProvider<Track>>(new TrackDataProvider());
container.Register<IDataProvider<Artist>>(new ArtistDataProvider());
}
}
}
在实际中,还会使用到很多的重载方法。比如在方法 RequestStartup 中配置表单验证,ConfigureRequestContainer 中配置自定义 IUserMapper ,ConfigureApplicationContainer 中注册外部的Ioc依赖项,ConfigureConventions 中设置网站应用中的静态文件夹,ApplicationStartup中处理异常。
一个自定义bootstrapper 示例
总结