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. Spring Cloud 系列之 Dubbo RPC 通信

    Dubbo 介绍 官网:http://dubbo.apache.org/zh-cn/ Github:https://github.com/apache/dubbo 2018 年 2 月 15 日,阿里 ...

  2. rust 函数-生命周期

    记录一下自己理解的生命周期. 每个变量都有自己的生命周期. 在c++里生命周期好比作用域, 小的作用域的可以使用大作用域的变量. 如果把这里的每个作用域取个名,那么就相当于rust里的生命周期注解. ...

  3. ​Shiro授权

    Shiro三种授权方式 编程式:通过写 if/else 授权代码块完成: Subject subject = SecurityUtils.getSubject(); if(subject.hasRol ...

  4. SSH网上商城一

    Java高级项目之SSH网上商城项目实战: 1.采用目前最主流的三大框架开发即Struts2+Spring+Hibernate框架整合开发.2.通过AJAX技术提供良好的用户体验.3.提供了邮箱激活的 ...

  5. GCC编译和链接过程

    GCC(GNU Compiler Collection,GNU编译器套件),是由 GNU 开发的编程语言编译器.它是以GPL许可证所发行的自由软件,也是 GNU计划的关键部分.GCC原本作为GNU操作 ...

  6. 线上redis问题修复:JedisConnectionException: Unexpected end of stream.

    经过: 项目上线后经常报 Unexpected end of stream.; nested exception is redis.clients.jedis.exceptions.JedisConn ...

  7. Python之浅谈多态和封装

    目录 组合 什么是组合 为什么使用组合 多态和多态性 多态 什么是多态? 多态性 好处 多态性 什么是多态性 封装 封装是什么意思? 隐藏 如何用代码实现隐藏 python 实际上是可以访问隐藏属性的 ...

  8. 洛谷 P1313 【计算系数】

    这道题只要肯动手还是挺水的 进入正题 我们先枚举几个找找规律(这里先省略x,y): k = 0 :\(1\) k = 1 : \(a\) \(b\) k = 2 : \(a^{2}\) \(2ab\) ...

  9. 什么是JSTL标签库?

    什么是JSTL? JSTL(JSP Standard Tag Library,JSP标准标签库)是一个不断完善的开放源代码的JSP标签库,是由apache的jakarta小组来维护的. 有什么作用? ...

  10. CentOS 关闭暂不需要的系统服务

    需要保留的服务:crond.iptables.irqbalance.microcode_ctl.network.random.sshd.syslog.local 一 .使用命令:ntsysv 打开选项 ...