如何将 .NetFramework WebApi 按业务拆分成多个模块
在 .NetFramework 中使用 WebApi ,在不讨论 微服务 的模式下,大部分都是以层来拆分库的 :
- 基础设施
- 数据存储层
- 服务层
- WeApi 层
- 一些其它的功能库
项目结构可能会像下面这样子
有些人可能会将其中的 数据存储层、服务层 按业务功能进行垂直拆分,
但是到了 WebApi 这层,就不得不把所向所有业务功能的 Controller 都堆在这儿了。
随着业务的堆积,WebApi 这层的代码量越来越大,耦合性也越来越强,越来越难维护。
…
……
………
…………
这时候,微服务 就出现了。
可是,微服务 给系统所带来的复杂程度是极高的,
在某些场景下,转 微服务 可以很好的解决这些问题,但是又会带来更多的新问题,
所以我们希望有一种模式,即能像 微服务 那样对代码进行垂直切分,又能保持简单易维护的 单体应用程序 模式。
打算在 单体应用程序 中解决这种趋于 臃肿 问题,我们可以借鉴 微服务 那种 按业务垂直拆分 的思想。
但是与 微服务 不同是,它依然是单启动程序,这个启动程序能够组织出散落在各个模块中的所有 WebApi 并暴露给外部。
换个角度思考,其实就是将业务 模块化 。
微软维护的 Ochard框架很好的实现了这些功能,但是使用 Orchard 可能会给你带来以下问题
- 这是一个非常重型的框架,代码量比较大,运行速度不佳
- 几乎没有什么中文的文档( 最多只能找到 HelloWorld 这样的浅显的教程 )
- 官网文档是英文的,对阅读有较高的要求,而且速度很慢,需要使用正确的阅读方式
- 系统中充斥着大量的隐匿约束( 在类型名称上的约束,前端更是使用了大量的 DynamicObject ,很难了解到到底包含了哪些可用 成员 )
....
于是我基于 Reface.AppStarter 开发了一套轻量级的模块化 WebApi 框架 【 Reface.AppStarter.WebApi 】,它实现了以下功能
- 垂直拆分你的 WebApi Controller 至不同的 Library
- 开箱即用的 Controller 构造函数注入
- 具备 Reface.AppStarter 中的 EventBus 和 CommandBus 功能,可以很好的进行模块间的通信
- 在 启动模块 决定启动哪些业务模块
使用 Reface.AppStarter.WebApi 很简单,它对原来的开发风格几乎没有什么影响,
下面将演示如何使用 Reface.AppStarter.WebApi 将 WebApi 项目拆分至各种模块
Step 1 - 创建空的 WebApi 项目
创建一个 WebApi 项目,但是你不需要在这里写任何的 Controller , 它只是你的启动程序,不需要为它编写任何与启动无关的代码。
为你的 WebApi 添加 Nuget 引用Reface.AppStarter 。
Step 2 - 创建业务库
创建业务 Library ,比如 Users,你将在这个 Library 中实现有关 Users 的所有功能,包括 Controller。
通过 Nuget 引用 Reface.AppStarter.WebApi
Step 3 - 在业务库中编写控制器
为 Users Library 添加一个 Controllers 的目录,并编写你的控制器
[ApiRoute("hello")]
public class HelloController : ApiController
{
[Route]
public string Get()
{
return "HelloWorld!";
}
}
Reface.AppStarter.WebApi 包含了编写一个 WebApi 的所有依赖项。
因此你只要通过 Nuget 添加了 Reface.AppStarter.WebApi 就可以编写属于你的 ApiController 。
如果你需要向 控制器 中注入一些其它的组件,你只要通过构造函数注入即可:
[ApiRoute("hello")]
public class HelloController : ApiController
{
private readonly IHelloService helloService; public HelloController(IHelloService helloService)
{
this.helloService = helloService;
} [Route]
public string Get()
{
return "HelloWorld!";
}
}
Step 4 - 编写业务库的 AppModule
为你的 Users Library 编写一个 AppModule 。
在 Reface.AppStarter 框架模式下,每一个 Library 都至少要提供一个 AppModule ,以供给其它模块依赖。
你的 Users 也不例外,
UsersAppModule 需要使用 WebApi 功能,因此 UsersAppModule 要依赖 WebApiAppModule
[WebApiAppModule]
public class UsersAppModule : AppModule
{
}
如果你还需要 自动配置、自动 IOC / DI 注册装配,那你也可以根据你的需求添加其它的 AppModule。
Step 5 - 让你的启动项目依赖 UsersAppModule
首先,你需要为你启动项目创建一个 AppModule ,比如 WebAppModule
[UsersAppModule]
public class WebAppModule : AppModule
{
}
然后你需要创建一个 Global.asax ,相信大家应该都知道这是个什么吧。
修改你的 Global.asax 文件,使其继承于 RefaceHttpApplication<T> ,这里的 T ,就是你的 WebAppModule。
public class MyWebApiApplication : RefaceHttpApplication<WebAppModule>
{
}
这样,就会在 Web 应用程序启动的时候,完成 Reface.AppStarter 中的所有过程。
提示 :
- 这个 RefaceHttpApplication<T> 只是封装了 AppSetup.Start 的过程,你也可以不继承此类,并手动完成对 AppSetup 的启动。
Step 6 - 配置文件
通过 RefaceHttpApplication<T> 启动,会以站点根目录的 app.json 文件作为 Reface.AppStarter 框架内的配置文件。
Reface.AppStarter.WebApi 内只有一个 Config 类型,它允许重新定义所有 WebApi 的路由前缀
{
"WebApi": {
"Prefix": "myapi"
}
}
你可以通过修改这个 Prefix 来修改所有控制器的前缀名称,( 默认值是 api )。
Step 7 - 运行
运行你的启动程序吧,并键入 /myapi/hello 你就会看到 HelloController 虽然写在了别的 Library 里,但是依然可以成功的访问。
至此就介绍了 Reface.AppStarter.WebApi 中的主要功能。
有关 Reface.AppStarter 相关功能,可以阅读 《https://www.cnblogs.com/ShimizuShiori/p/12610668.html》
有关 事件总线,会在后面的文章中向大家介绍。
如何将 .NetFramework WebApi 按业务拆分成多个模块的更多相关文章
- 将log4j2的配置文件log4j2.xml拆分成多个xml文件
在日常的项目开发中,我们可能会使用log4j2分离系统日志与业务日志 ,这样一来,log4j2.xml 这个配置文件可能就会变得非常臃肿.庞大,那么我们可以将这个文件拆分成多个配置文件吗? 答案是肯定 ...
- 为什么要把系统拆分成分布式的,为啥要用Dubbo?
阅读本文大概需要 6 分钟. 作者:yanglbme 1.面试题 为什么要进行系统拆分?如何进行系统拆分?拆分后不用 dubbo 可以吗? 2.面试官心里分析 从这个问题开始就进行分布式系统环节了,好 ...
- 电商架构设计-通过系统和业务拆分,遵循单一职责原则SRP,保障整个系统的可用性和稳定性
个人观察 1.通过系统和业务拆分,遵循单一职责原则SRP,保障整个系统的可用性和稳定性. 2.单一职责原则SRP,真的很关键,广大程序员需要不断深入理解这个原则. 3.架构图是架构师的重要输出,通过图 ...
- UTF-8编码的字符串拆分成单字、获取UTF-8字符串的字符个数的代码及原理
一.字符编码简介 1. ASCII码 在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(by ...
- Oracle字符串行拆分成列的三种方式
Oracle字符串行拆分成列的三种方式 --muphy 开发过程中经常会遇到将前台多个值用逗号连接一同传递到后台查询,这个用逗号连接的字符串分隔的每个字符串分别对应Oracle数据库表的不同行. 如下 ...
- [Swift]LeetCode842. 将数组拆分成斐波那契序列 | Split Array into Fibonacci Sequence
Given a string S of digits, such as S = "123456579", we can split it into a Fibonacci-like ...
- 将excel按照某一列拆分成多个文件(方案整理)
1解决方案:将excel按照某一列拆分成多个文件 https://blog.csdn.net/ntotl/article/details/79141314 2遇到的问题:解决vbe6ext.olb不能 ...
- Oracle数据库字段数据拆分成多行(REGEXP_SUBSTR函数)
做多选功能时为了简便,会在某个字段中存储多个值,保存时虽然省事,但后续的查询统计时还需要拆分数据才行,因此这时需要将字段内的值分成多行以便后续使用. 下面这个例子实现了字段内数据的拆分: --创建测试 ...
- sql 表值函数-将一个传入的字符串用2中分隔符拆分成临时表
USE [tms]GO/****** Object: UserDefinedFunction [dbo].[fn_StrToTable_Double] Script Date: 2017/4/26 9 ...
随机推荐
- python学习的新篇章--面向对象
面向对象的学习笔记 关键要素: 类:class 用来描述具有相同的属性和方法的对象的集合,它定义了该集合中每个对象所共有的属性和方法. 数据成员: 类的不同属性数据 对象: 类的一个实例 ...
- flask 链接mysql数据库 小坑
#config.py MYSQL_NAME = 'root' MYSQL_PASSWORD = 'zyms90bdcs' MYSQL_HOST = 'xxxx' MYSQL_POST = ' MYSQ ...
- Java集合01——List 的几个实现类,了解一下?
从本文起,我们将开始分享 Java 集合方面的知识,关注公众号「Java面典」了解更多 Java 知识点. List 是继承于 Collection 的接口,其实现类有 ArrayList,Linke ...
- Drf(DjangoRestFramewok)
第一部分 问题 1.前后端分离? vue.js 后端给前段返回json数据 2.移动端盛行. app 后端给app返回json数据 3.PC端应用? crm项目,前段后端一起写,运行在浏览器上. 一般 ...
- Java抽象类和接口的区别及联系
抽象类 注:先将抽象类中的两种方法解释完,再综合解释抽象类 抽象方法 应用场景:其下所有子类都应该有该方法但是大部分子类具体的执行步骤是有所不同的. 必须重写:也可以说"必须实现" ...
- 爬虫 | cnblog文章收藏排行榜(“热门文摘”)
目录 需要用的module 单页测试 批量抓取 数据保存 背景说明 因为加入cnblog不久,发现上面有很多优秀的文章. 无意中发现cnblog有整理文章的收藏排行榜,也就是热门文摘. 不过有点坑的是 ...
- tars之springboot的初步使用
公司要求使用tars框架,现学习的,听老大讲的经验和看的一些技术博客,感觉和SpringCloud有些相似,不过内部有自己的规范,基于rpc实现的服务与服务之间的远程调用,而cloud的远程调用是基于 ...
- pycharm+keras+yolo3的使用和自选模型的训练中遇到的坑
1.TensorFlow版本的问题 报错:RuntimeError: `get_session` is not available when using TensorFlow 2.0. 解决办法:这个 ...
- Centos7配置IP地址和DNS
目录 一.查看IP地址 1.ifconfig命令 2.ip addr命令 二.配置网卡 1.动态IP地址 2.静态IP地址 3.重启网卡 三.注意事项 四.本地虚拟机设置静态IP后不能上网的解决方法 ...
- Unity 游戏框架搭建 2019 (九~十二) 第一章小结&第二章简介&第八个示例
第一章小结 为了强化教程的重点,会在合适的时候进行总结与快速复习. 第二章 简介 在第一章我们做了知识库的准备,从而让我们更高效地收集示例. 在第二章,我们就用准备好的导出工具试着收集几个示例,这些示 ...