Reface.AppStarter 基本示例

Reface.AppStarter 向应用层提供以下几项 核心 功能

  • 以模块化组织你的应用程序
  • 自动注册组件至 IOC 容器
  • 自动映射配置文件至配置类
  • 在模块定义类中额外追加组件至 IOC 容器
  • 在模块定义类中额外追加配置类
  • 事件总线

这些功能允许让开发者将功能拆分至各个小粒度模块,
当使用某个模块时,只需要向模块添加一个依赖,即可开启所有功能,
实现了整个模块的开箱即用。


本文将介绍 Reface.AppStarter 中最常用的三个功能 自动注册组件至 IOC 容器自动映射配置文件模块化

自动注册组件至 IOC 容器

使用 IOC 容器 往往分为两个阶段

  • 配置阶段
  • 使用阶段

配置阶段 我们可能会选择 配置文件对所有依赖的程序集反射对指定程序反射硬编码 等方式对组件进行 注册

对所有依赖的程序集反射 ,怎么看都是一种即笨重又有些呆板的方法。

然而另外几个方案在多模块化的项目里中 ,
也无法很好的工作,
它们各自需要在系统启动时,明确一些信息 :

  • 一共需要读取哪些配置文件,这些文件在各个子模块的哪儿
  • 一共需要对哪些程序集进行反射
  • 那些负责硬编码注册的类型都在哪儿

如果上述的信息没有被收集完整,那么程序会因为没有注册全部组件而无法正确运行。


事实上

在大多数情况下,开发者在编写一个 接口 和一个 实现 时,就已经确定 注册关系
只有那些可能面临 策略模式 ,或者存在多客户端适配的情况下,这种 注册关系 无法确定。

所以通过 Attribute 加 扫描,是一种很好的 自动化注册 手段。

假定我们需要实现下面的接口

// Services/IUserService.cs
public interface IUserService
{
    void CreateUser(User user);
}

实现过程大致如下

// Services/DefaultUserService.cs
public class DefaultUserService : IUserService
{
    private readonly IRepository<User> userRepo ;

    public DefaultUserService(IRepository<User> userRepo)
    {
        this.userRepo = userRepo;
    }

    public void CreateUser(User user)
    {
        this.userRepo.Insert(user);
    }
}

使用 Reface.AppStarter ,你不再需要编写额外的代码将这个 DefaultUserService 注册到 IUserService 上。
你只需要为 DefaultUserService 添加一个 ComponentAttribute

// Services/DefaultUserService.cs
[Component]
public class DefaultUserService : IUserService
{
    // ...
}

这个 特征 就是通知 Reface.AppStarter 将该类型注册到 IOC 容器 中,并注册到它所有实现的接口类型上。


在由 Reface.AppStarter 构建的系统中,程序不是单纯的由 程序集 组成,而是由 应用模块 组成。
应用模块 不仅包含了 程序集 原有的功能,还能够体系与其它 应用模块 的依赖关系。

现在我们为刚才 DefaultUserService 所在的 程序集 编写一个 应用模块 的类型。

// UserAppModule.cs
[ComponentScanAppModule]
public class UserAppModule : AppModule
{

}

这就是一个 用户应用模块 ( 所有的 应用模块 应当从 AppModule 继承 ),
它依赖了一个 ComponentScanAppModule应用模块

ComponentScanAppModule 会将 目标应用模块 中标记了 ComponentAttribute 的类型注册到 IOC 容器中。

运行程序

public static void Main(String[] args)
{
    var app = AppSetup.Start<UserAppModule>();
    IUserService service = app.CreateComponent<IUserService>();
    // you can use service now;
}

除了直接启动 UserAppModule ,
也可以将 UserAppModule 加到别的 应用模块 上,这个 自动注册 同样有效。
基于这样的方式, UserAppModule 完全可以开箱即用。

也可以说,任何一个 应用模块 都可以开箱即用。

自动映射配置文件

配置文件总是存在的, .NetFramework 提供了一整套 Configuration 方案。
但是这个方案略显笨重,并且在配置过程完全没有提示,必须依赖大量的文档说明。

很明显 JSONXML 轻巧很多,
并且还有 JsonSchema 可以向 IDE 提供提示功能。

所以 Reface.AppStarter 选择了 JSON 作为配置文件的格式 ,
Reface.AppStarter 会读取一个包含了所有配置的 JSON 文件,
将配置中的值映射的 对应 的类型和属性中,
并将这些 类型 以单例的模式注册到 IOC 容器中。


UserAppModule 为例,我们为其开发一个 配置类
配置类 就是 Reface.AppStarter 在解析 JSON 文件后反序列化的目标类型。

为一个类型添加 ConfigAttribute 就会通知 Reface.AppStarter : "嘿,这有一个配置类"

下面的例子表示,我们可以通过配置文件指定 根用户的信息

// Configs/UserConfig
[Config("User")]
public class UserConfig
{
    public string RootUserName { get; set; } = "admin";
    public string RootUserPassword { get; set; } = "888888";
}

ConfigAttribute 的构造函数中指定的 User 表示从配置文件的 User 节点中读取配置,配置文件大至如下:

{
    "User" : {
        "RootUserName" : "ROOT",
        "RootUserPassword" : "123456789"
    }
}

如果没有配置文件,或者配置文件中没有编写 User 则会使用属性中指定的默认值将配置类实例注册到 IOC 容器 中。

通过构造函数注入配置类就可以使用它们。

// Services/DefaultUserService.cs
public class DefaultUserService : IUserService
{
    private readonly IRepository<User> userRepo;
    private readonly UserConfig userConfig;

    public DefaultUserService(IRepository<User> userRepo, UserConfig userConfig)
    {
        this.userRepo = userRepo;
        this.userConfig = userConfig;
    }

    public void CreateUser(User user)
    {
        if(user.Name == userConfig.RootUserName)
            throw new SomeException("无效的用户名,不能创建该用户");
        this.userRepo.Insert(user);
    }
}

ComponentScanAppModule 一样,需要为 UserAppModule 添加一样依赖来开启 自动映射配置文件 的功能。

// UserAppModule.cs
[ComponentScanAppModule]    // 开启自动扫描注册组件
[AutoConfigAppModule]       // 开启自动映射配置文件
public class UserAppModule : AppModule
{

}

现在启动 UserAppModule
或者将 UserAppModule 添加到其它 应用模块 的依赖项中,
这些功能都会被启用。

AppSetup.Start() 默认读取 app.json 文件,
若配置文件不存在,则直接使用 配置类 的默认属性值。

关于配置智能提示

通过 AppSetup.Start<T>() 运行程序后,会在输出目录下产生一个 app.schema.json 文件。

为你的 app.json 添加 $schema 属性,值指向 app.schema.json 文件,就可以得到智能提示功能:

TS1

TS2

你也可以通过上图显示的属性关闭生成 app.schema.json 的功能。


相关链接

原文地址:https://www.cnblogs.com/ShimizuShiori/p/13321520.html