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 文件,就可以得到智能提示功能:

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


相关链接

Reface.AppStarter 基本示例的更多相关文章

  1. Reface.AppStarter 框架初探

    Reface.AppStarter 是一种基于 .NetFramework 的应用程序启动模式,使用该启动模式,你可以轻松的得到以下功能 : IOC / DI 自动注册与装配 简化配置 垂直模块化你的 ...

  2. Reface.AppStarter 类型扫描 —— 获得系统中所有的实体类型

    类型扫描 是 Reface.AppStarter 提供的最基本.最核心的功能. AutoConfig , ComponentScan 等功能都是基于该功能完成的. 每一个使用 Reface.AppSt ...

  3. 事件总线功能库,Reface.EventBus 详细使用教程

    Reface.AppStarter 中的事件总线功能是通过 Reface.EventBus 提供的. 参考文章 : Reface.AppStarter 框架初探 使用 Reface.EventBus ...

  4. Reface.NPI 方法名称解析规则详解

    在上次的文章中简单介绍了 Reface.NPI 中的功能. 本期,将对这方法名称解析规则进行详细的解释和说明, 以便开发者可以完整的使用 Reface.NPI 中的各种功能. 基本规则 方法名称以 I ...

  5. EF 太重,MyBatis 太轻,ORM 框架到底怎么选 ?

    以 EF 为代表的基于 Linq 的 ORM 框架总是 很重. 他们的功能早已超出了一个 ORM 的范畴, ORM 是 Object Relational Mapping ,从名字上看,其初衷是将 数 ...

  6. 如何将 .NetFramework WebApi 按业务拆分成多个模块

    在 .NetFramework 中使用 WebApi ,在不讨论 微服务 的模式下,大部分都是以层来拆分库的 : 基础设施 数据存储层 服务层 WeApi 层 一些其它的功能库 项目结构可能会像下面这 ...

  7. 代理模式是什么?如何在 C# 中实现代理模式

    代理模式 并不是日常开发工作中常常用到的一种设计模式,也是一种不易被理解的一种设计模式.但是它会广泛的应用在系统框架.业务框架中. 定义 它的 定义 就如其它同大部分 设计模式 的定义类似,即不通俗也 ...

  8. Swift3.0服务端开发(一) 完整示例概述及Perfect环境搭建与配置(服务端+iOS端)

    本篇博客算是一个开头,接下来会持续更新使用Swift3.0开发服务端相关的博客.当然,我们使用目前使用Swift开发服务端较为成熟的框架Perfect来实现.Perfect框架是加拿大一个创业团队开发 ...

  9. .NET跨平台之旅:将示例站点升级至 ASP.NET Core 1.1

    微软今天在 Connect(); // 2016 上发布了 .NET Core 1.1 ,ASP.NET Core 1.1 以及 Entity Framework Core 1.1.紧跟这次发布,我们 ...

随机推荐

  1. STM32单片机应用与全案例实践 /stm32自学笔记 第二版 pdf

    STM32单片机应用与全案例实践pdf https://pan.baidu.com/s/16WrivuLcHvLTwS__Zcwl6Q 4rj3 stm32自学笔记 第二版 pdf https://p ...

  2. 二分查找法demo

    正文 中午闲着有点时间,做个demo睡觉去,这个例子网上应该都有,自己只是敲一下给自己做个记录. public static void main(String[] args) { int[] whit ...

  3. 【Spring注解驱动开发】关于BeanPostProcessor后置处理器,你了解多少?

    写在前面 有些小伙伴问我,学习Spring是不是不用学习到这么细节的程度啊?感觉这些细节的部分在实际工作中使用不到啊,我到底需不需要学习到这么细节的程度呢?我的答案是:有必要学习到这么细节的程度,而且 ...

  4. python将指定目录下的所有文件夹用随机数重命名

    我的目的在于打乱数据顺序,便于GAN训练: import random import os path = 'hunhe_7' #目标文件夹 listname = os.listdir(path) #遍 ...

  5. jQuery制作div板块拖动层排序

    html结构: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  6. python编码--解码

    在py3中只有两种数据类型:str  bytes str:  存unicode(万国码)编码--全球通用的 bytes:存的是16进制的 1.str s='ehllo 丽庆'  --->它存在内 ...

  7. 让 JavaScript 与 CSS 和 Sass 对话

    JavaScript 和 CSS 已经并存超过了 20 年.但是在它们之间共享数据非常困难.当然也有大量的尝试.但是我所想到的是一些简单而直观的内容——不涉及结构更改,而是使用 CSS 自定义属性甚至 ...

  8. kibana限制用户只具备读图的权限

    假设需求 因为业务需要将日志系统收集到的信息进行图表化展示并交付到用户进行业务交流. 解决方案 这个需求看着似乎蛮简单的,如何解决? 1.对需要的数据进行过滤制作图表 2.对用户的权限限制为只读级别, ...

  9. vue+elementUI 图片上传问题

    图片上传问题,获取后台的图片,并点击可以更换图片,并把图片存储到数据库中: (1)在编辑页面上,action指的图片上传的地址,header指请求头: (2)因为element-ui有自己上传的接口, ...

  10. Mysql如何取当日的数据

    下面的sql语句可以取出当日的数据 SELECT * FROM table WHERE 时间字段 BETWEEN DATE_FORMAT(NOW(),'%Y-%m-%d 00:00:00') AND ...