你是不是羡慕 Java SpringBoot 里功能强大的 @注解功能, Spring Boot 倡导是一种开箱即用, 方便快捷, 约定优于配置的开发流程, 虽然现在. NET Core 也往相同的方向走, 但在使用上总有点别扭, 目前市面上貌似还没有轻量级的真正意义上的开箱即用的基于. NET Core 的框架.
想想多年前自己开发基于配置的 DevFx 开发框架, 因为需要配置, 造成开发人员苦不堪言, 而且还容易配置错误, 导致各种奇怪的错误; 于是便有全新重写 DevFx 框架的想法, 经过 N 个月的奋战, 终于可以放出来用了.
框架不求功能全面, 只求使用方便, 灵活.
目前框架提供基于 Attribute 的 IoC DI 容器, 完全可以面向接口编程了; 提供轻量级的业务参数配置方案, 未来计划作为集中配置的基础; 提供极简但不失灵活的数据访问框架, 类似 mybatis 基于 sql 的数据访问; 还有基于 HTTP/JSON 的远程调用方案(以优雅的本地调用方式来远程调用); 主要是以上几个功能.
框架是基于. NET Standard 2.0 开发, 理论上. NET Framework 4.6.1 也能使用, 因为框架已完全重新重写了, 命名空间啥的都有改变, 所以不兼容之前的版本, 目前版本是 5.0.2.
OK,show me the code. 下面让我们来快速入门, 看看怎么个开箱即用.
打开 VS2019, 建立基于. NET Core 2.2 或 3.0 的控制台项目 ConsoleApp1, 下面的例子是基于. NET Core 3.0 的. 使用 NuGet 安装 DevFx 5.0.2 版本
上图, 忽略 DevFx.*, 这是老旧版本, 目前基于. NET Standard 只有一个包, 就是 DevFx
创建业务逻辑接口和实现类
- using DevFx;
- namespace ConsoleApp1
- {
- // 业务逻辑接口,[Service]特性告诉 DevFx 这个接口需要被 DI
- [Service]
- public interface IMyService
- {
- string GetUserName(string userId);
- }
- }
- using DevFx;
- using System;
- namespace ConsoleApp1
- {
- // 业务逻辑实现类,[Object]特性告诉 DevFx 这个类需要放入到 IoC 容器里, DevFx 会扫描这个类实现了哪些接口, 并做映射
- [Object]
- internal class MyService : IMyService
- {
- public string GetUserName(string userId) {
- return $"{userId}_{DateTime.Now.Ticks}";
- }
- }
- }
开始调用逻辑
- using DevFx;
- using System;
- namespace ConsoleApp1
- {
- class Program
- {
- static void Main(string[] args) {
- // 控制台程序需要显式调用框架的初始化方法
- //ASP.NET Core(通用主机)可以使用 UseDevFx 扩展方法来初始化框架
- ObjectService.Init();
- // 获取接口实现类的实例
- var myservice = ObjectService.GetObject<IMyService>();
- Console.WriteLine(myservice.GetUserName("IamDevFx"));
- // 还能直接获取 MyService 类的实例
- var myservice1 = ObjectService.GetObject<MyService>();
- //2 种方式获取的实例是同一个
- Console.WriteLine($"myservice={myservice.GetHashCode()}{Environment.NewLine}myservice1={myservice1.GetHashCode()}");
- }
- }
- }
运行下:
是不是很简单? 开箱即用!
接下介绍下自动装配的例子
我们建立另外一个业务逻辑接口和相应的实现类, 同样分别标上 [Service] 和[Object]
- using DevFx;
- namespace ConsoleApp1
- {
- [Service]
- public interface IBizService
- {
- string GetUserDisplayName(string userId);
- }
- [Object]
- internal class BizService : IBizService
- {
- public string GetUserDisplayName(string userId) {
- return "IamBizService";
- }
- }
- }
改下之前的业务类 MyService
- using DevFx;
- using System;
- namespace ConsoleApp1
- {
- // 业务逻辑实现类,[Object]特性告诉 DevFx 这个类需要放入到 IoC 容器里, DevFx 会扫描这个类实现了哪些接口, 并做映射
- [Object]
- internal class MyService : IMyService
- {
- // 自动装配(注入)
- [Autowired]
- protected IBizService BizService { get; set; }
- public string GetUserName(string userId) {
- return $"{userId}_{DateTime.Now.Ticks}_{this.BizService.GetUserDisplayName(userId)}";
- }
- }
- }
运行下:
接下来介绍下基于 xml 的配置, 可能有些同学会问,.NET Core 不是自带配置了么? 别急, 看下我们的使用方式你就清楚谁便捷了.
业务参数指的比如微信的 API 接口地址, APPID 等程序里需要使用的, 或者一些开关之类的参数
首先定义需要承载业务参数的接口
- using DevFx.Configuration;
- namespace ConsoleApp1
- {
- // 定义需要承载业务参数的接口,[SettingObject("~/myservice/weixin")]告诉框架这是一个配置承载对象
- // 其中~/myservice/weixin 为配置在配置文件里的路径
- [SettingObject("~/myservice/weixin")]
- public interface IWeixinSetting
- {
- string ApiUrl { get; }
- string AppID { get; }
- string AppKey { get; }
- }
- }
使用自动装配特性, 装配到业务逻辑里, 我们修改下 MyService 类
- using DevFx;
- using System;
- namespace ConsoleApp1
- {
- // 业务逻辑实现类,[Object]特性告诉 DevFx 这个类需要放入到 IoC 容器里, DevFx 会扫描这个类实现了哪些接口, 并做映射
- [Object]
- internal class MyService : IMyService
- {
- // 自动装配(注入)
- [Autowired]
- protected IBizService BizService { get; set; }
- // 配置自动注入
- [Autowired]
- protected IWeixinSetting WeixinSetting { get; set; }
- public string GetUserName(string userId) {
- return $"{userId}_{DateTime.Now.Ticks}_{this.BizService.GetUserDisplayName(userId)}_weixin={this.WeixinSetting.ApiUrl}";
- }
- }
- }
在项目里添加 App.config, 并设置为有更新就输出
App.config 内容如下:
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <devfx>
- <myservice>
- <weixin apiUrl="https://api.weixin.qq.com/sns/oauth2/access_token"
- appId="1234567890" appKey="0123456789" />
- </myservice>
- </devfx>
- </configuration>
运行下:
最后介绍下类似 mybatis 的数据访问是如何开箱即用的, 因为涉及到数据库, 稍微复杂些, 但还是很方便的.
我们以操作 MySQL 为例, 首先需要使用 NuGet 安装 MySQL 驱动包, 目前框架默认使用社区版的 MySQL 驱动: MySqlConnector
定义我们的数据访问层接口
- using ConsoleApp1.Models;
- using DevFx;
- using DevFx.Data;
- namespace ConsoleApp1.Data
- {
- // 定义数据操作接口,[DataService]告诉框架这是一个数据操作接口
- [DataService(GroupName = "MyService")]
- public interface IMyDataService : ISessionDataService
- {
- EventMessage GetEventMessageByID(string id);
- }
- }
在项目中, 添加一个. sqlconfig 文件, 用来编写对应的 Sql 语句, 并把这个文件按嵌入资源形式设置
sqlconfig 内容如下:
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <devfx>
- <data>
- <statements name="MyService">
- <add name="GetEventMessageByID">
- <sql>
- <![CDATA[SELECT * FROM EventMessages WHERE MessageGuid = @ID]]>
- </sql>
- </add>
- </statements>
- </data>
- </devfx>
- </configuration>
相信聪明的你能看出对应关系
然后就是在 App.config 里配置链接字符串, 如下
- <?xml version="1.0" encoding="utf-8" ?>
- <configuration>
- <devfx>
- <data debug="true">
- <connectionStrings>
- <add name="EventMessageConnection" connectionString="Database=EventMessages;Data Source = 数据库 IP;User ID = 数据库用户; Password = 密码; Character Set=utf8" providerName="System.Data.MySqlClient" />
- </connectionStrings>
- <dataStorages defaultStorage="EventMessageStorage">
- <add name="EventMessageStorage" connectionName="EventMessageConnection" type="MySql" />
- </dataStorages>
- </data>
- <myservice>
- <weixin apiUrl="https://api.weixin.qq.com/sns/oauth2/access_token"
- appId="1234567890" appKey="0123456789" />
- </myservice>
- </devfx>
- </configuration>
调整下我们 MySerivce 类
- using ConsoleApp1.Data;
- using DevFx;
- using System;
- namespace ConsoleApp1
- {
- // 业务逻辑实现类,[Object]特性告诉 DevFx 这个类需要放入到 IoC 容器里, DevFx 会扫描这个类实现了哪些接口, 并做映射
- [Object]
- internal class MyService : IMyService
- {
- // 自动装配(注入)
- [Autowired]
- protected IBizService BizService { get; set; }
- // 配置自动注入
- [Autowired]
- protected IWeixinSetting WeixinSetting { get; set; }
- // 数据访问接口自动注入
- [Autowired]
- protected IMyDataService MyDataService { get; set; }
- public string GetUserName(string userId) {
- var msg = this.MyDataService.GetEventMessageByID("0000e69f407a4b69bbf3866a499a2eb6");
- var str = $"EventMessage:{msg.MessageGuid}_{msg.Category}_{msg.Priority}_{msg.CreatedTime}";
- return $"{userId}_{DateTime.Now.Ticks}_{this.BizService.GetUserDisplayName(userId)}_weixin={this.WeixinSetting.ApiUrl}{Environment.NewLine}{str}";
- }
- }
- }
运行下:
当然数据访问不仅仅是查询, 还应该有 CRUD, 分页以及事务才完整, 这些后续会详细展开.
OK, 上面就是这些核心功能的展示, 另外框架还支持自定义 Attribute 的处理方便自行扩展.
后续会比较详细介绍实现原理以及对框架的拓展, 比如服务注册发现, 配置中心等等.
有兴趣的同学可以一起共同讨论维护, 项目开源地址在: https://github.com/mer2/devfx
码字不容易啊, 感兴趣的可以去 star 下.
示例代码在此: https://files.cnblogs.com/files/R2/ConsoleApp1.zip
来源: https://www.cnblogs.com/R2/p/11583952.html