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 方案。
但是这个方案略显笨重,并且在配置过程完全没有提示,必须依赖大量的文档说明。
很明显 JSON 比 XML 轻巧很多,
并且还有 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 基本示例的更多相关文章
- Reface.AppStarter 框架初探
Reface.AppStarter 是一种基于 .NetFramework 的应用程序启动模式,使用该启动模式,你可以轻松的得到以下功能 : IOC / DI 自动注册与装配 简化配置 垂直模块化你的 ...
- Reface.AppStarter 类型扫描 —— 获得系统中所有的实体类型
类型扫描 是 Reface.AppStarter 提供的最基本.最核心的功能. AutoConfig , ComponentScan 等功能都是基于该功能完成的. 每一个使用 Reface.AppSt ...
- 事件总线功能库,Reface.EventBus 详细使用教程
Reface.AppStarter 中的事件总线功能是通过 Reface.EventBus 提供的. 参考文章 : Reface.AppStarter 框架初探 使用 Reface.EventBus ...
- Reface.NPI 方法名称解析规则详解
在上次的文章中简单介绍了 Reface.NPI 中的功能. 本期,将对这方法名称解析规则进行详细的解释和说明, 以便开发者可以完整的使用 Reface.NPI 中的各种功能. 基本规则 方法名称以 I ...
- EF 太重,MyBatis 太轻,ORM 框架到底怎么选 ?
以 EF 为代表的基于 Linq 的 ORM 框架总是 很重. 他们的功能早已超出了一个 ORM 的范畴, ORM 是 Object Relational Mapping ,从名字上看,其初衷是将 数 ...
- 如何将 .NetFramework WebApi 按业务拆分成多个模块
在 .NetFramework 中使用 WebApi ,在不讨论 微服务 的模式下,大部分都是以层来拆分库的 : 基础设施 数据存储层 服务层 WeApi 层 一些其它的功能库 项目结构可能会像下面这 ...
- 代理模式是什么?如何在 C# 中实现代理模式
代理模式 并不是日常开发工作中常常用到的一种设计模式,也是一种不易被理解的一种设计模式.但是它会广泛的应用在系统框架.业务框架中. 定义 它的 定义 就如其它同大部分 设计模式 的定义类似,即不通俗也 ...
- Swift3.0服务端开发(一) 完整示例概述及Perfect环境搭建与配置(服务端+iOS端)
本篇博客算是一个开头,接下来会持续更新使用Swift3.0开发服务端相关的博客.当然,我们使用目前使用Swift开发服务端较为成熟的框架Perfect来实现.Perfect框架是加拿大一个创业团队开发 ...
- .NET跨平台之旅:将示例站点升级至 ASP.NET Core 1.1
微软今天在 Connect(); // 2016 上发布了 .NET Core 1.1 ,ASP.NET Core 1.1 以及 Entity Framework Core 1.1.紧跟这次发布,我们 ...
随机推荐
- 详说tcp粘包和半包
tcp服务端和客户端建立连接后会长时间维持这个连接,用于互相传递数据,tcp是以流的方式传输数据的,就像一个水管里的水一样,从一头不断的流向另一头. 理想情况下,发送的数据包都是独立的, 现实要复杂一 ...
- PHP丨PHP基础知识之条件语IF判断「理论篇」
if语句是指编程语言(包括c语言.C#.VB.java.php.汇编语言等)中用来判定所给定的条件是否满足,根据判定的结果(真或假)决定执行给出的两种操作之一. if语句概述 if语句是指编程语言(包 ...
- Vmaware克隆虚拟机后无法上网
问题: 使用快照克隆了一台虚拟机 打开后发现无法上网,ifconfig查看状态 解决办法: 1.点击右下角的网络设置,点击设置,查看mac地址与文件/etc/udev/rules.d/70-persi ...
- OpenCV开发笔记(六十五):红胖子8分钟带你深入了解ORB特征点(图文并茂+浅显易懂+程序源码)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- 使用spring-test时报错
java.lang.NoClassDefFoundError: org/springframework/core/annotation/MergedAnnotations$SearchStrategy ...
- day01---学习Mysql高级性能优化1
Mysql逻辑架构图
- 入门大数据---Spark部署模式与作业提交
一.作业提交 1.1 spark-submit Spark 所有模式均使用 spark-submit 命令提交作业,其格式如下: ./bin/spark-submit \ --class <ma ...
- ubuntu18.04安装nodejs最新版、指定版 12.x 14.x
今天准备在 ubuntu 服务器里面安装 nodejs 版本,ubuntu 18.04 仓库 nodejs 默认是 8.x 版本. 1. 通过 apt 安装 nodejs 在 Ubuntu 18.04 ...
- JDK8--01:JDK8简介
一.新特性1.lambda表达式(重点)2.函数式接口3.方法引用与构造器引用4.Stream API(重点)5.接口中的默认方法和静态方法6.新时间日期API7.其他新特性 二.特点: 1.速度更快 ...
- 函数进化到Lambda表达式的三过程
假如我们想要从一个整型数组中取出其中是奇数的选项,其实现方式有很多, 接下来通过三种方法的对比理解Lambda表达式的用途,需要了解的朋友可以参考下 //声明委托类型 public d ...