零基础ASP.NET Core WebAPI团队协作开发

零基础ASP.NET Core WebAPI团队协作开发

相信大家对“前后端分离”和“微服务”这两个词应该是耳熟能详了。网上也有很多介绍这方面的文章。我这里提这个是因为接下来我要分享的内容和这个有些关联。

 

随着前端应用场景的繁荣,用户体验需求的提高,原先传统的后端渲染页面返回给前端展示的模式面临挑战。后端工作除了处理数据逻辑还得适应界面UI的业务,越来越不堪负重。前端的重要性逐渐体现出来,在这种情况下使用前后端分离模式开发的逐渐增多。

 

前端框架(比如Vue/Angular/React)的发力,大厂的推广使用,前后端分离已经很成熟。包括传统信息化这块以前使用传统WebMVC模式的开发BS应用有些都逐步转为前后端分离模式。特别是开发人员分工之后专注做好各自的工作,效率更高,做出来的产品也就更好。

 

一、应用场景

1浏览器端(Vue/Angular/React+服务端API

2桌面客户端(mfc/winform/wpf+服务端API

3移动客户端(各种App/App内置浏览器)+服务端API

4、其他终端(大数据展示平台/报表展示平台)+服务端API

 

客户端越来越强调轻量化,交互体验,不在满足于能用。服务端端只管提供API数据,这样业务逻辑大多在服务端处理,随着需求增加服务端的模块会越来越多。但是有些接口是共用的,有些是根据业务变动的,还有的API新旧版本过渡更新替换等等是服务端api要考虑的事情。设计好API开发框架面灵活应对这么多场景就很有必要了。

 

原先可能会做一个单体式应用,把所有用到的接口都加进去。但这样粒度很粗,如果某个场景下只使用了部分接口,那也得把这整个应用部署,无法做到按需添加。还有就是可能要修改其中部分方法,需要整体重新编译发布。这都存在可能影响其他模块的风险。

服务端任务量大了,怎么分工?这个时候单体明显已经不适用了。这里就引出了微服务。对微服务可能每个人有不同的理解,但有一点是有共识的,就是把一个大的单体式应用根据功能模块拆分,这样粒度细分之后很多接口就可以共用。之后的修改增加都是可以按需发布部署,局部出现问题不会影响整体。

 

这个服务的粒度怎么拆分也是需要慎重考虑的问题。除了功能拆分还得考虑人员匹配。

案例场景:一个系统有10个子系统(模块),每个子系统(模块)又有10个功能,每个功能再具体又可能有20左右的方法代码。

 

这个案例,最后大概有2000个方法代码。

如果开始安排10人的团队开发,中途因为项目紧急再增加了10个人进来,总共变成了20人,项目组怎么做才能快速适应这种人员变动。

有时候不是人越多越能做好事情,在人员增加情况下除了增加沟通协调成本,实际情况会遇到新加的人参与进来的门槛很高,不能快速着手展开工作,有时候还会出现不知道从何入手的困境。这就是因为拆分的不合理,任何的改动可能会影响到他人。这样虽然为了赶进度加人了,但实际的效果却不是很理想。

 

二、功能拆分分析

怎么拆分这有两个极端例子

1、粒度最粗,全部在一个解决方案(极端例子,类似单体式应用,适合一人开发)

2、粒度最细,细分到每个方法一个解决方案(极端例子,实际肯定不会这样做)

 

实际项目中功能拆分就是在这两个极端情况之间找适合的平衡点。具体拆分到多大的粒度,这个就只能是根据具体项目情况具体分析了。但是微服务可能是建议往细的方向拆。

如果是项目型的会发现如果拆的太细,上线一套系统要带N个接口,运维实施都很麻烦;如果是做平台型的产品可能就是有限的几套系统,不会随着项目铺开太多定制化。也就没有了项目型里面的经常部署实施等繁琐的问题。

比如上面的案例,一般都是先根据子系统拆分,具体到每个子系统,有一人或多人开发也有后期临时加入的情况。每个子系统一套接口还是比较合适的。

 

实际情况项目型比较多,考虑实施运维情况拆分的粒度不会太细,让实施去部署太多业务接口会把他们逼疯。如果有和我类似情况的下面的方案提供了一种解决办法。开发时候可以横向任意扩展,新加入的人员分配任务清晰,不用担心有耦合冲突。发布部署也不会因为粒度太细,增加部署工作量。总结就是插件式开发,微服务部署。

 

我们都知道vs里面建立一个解决方案,两三个开发人员在同一个解决方案里面开发,只要协调好还行,如果再加入人员,参与的开发人员一旦多了,就算分工好做各自模块,但还是会存在一个些冲突,比如增加文件,增加引用等等都会引起项目文件或者解决方案文件冲突问题。而且这种情况代码权限还不好细分控制。

 

最好的方式是每个开发人员做的事情都在自己的解决方案里面,只要是公共使用的引用协调好大家使用统一的版本,其他的自己完全可控,完全不用担心影响他人,或者他人的修改影响自己。

 

大家可以看下这个 github上面dotnet基础类库 如图1。

 

1

 

这是dotnet基础库的源码,每个基础类库都是单独一个解决方案维护,随便点一个进去看下,如图2

 

2

每个类库都有独立解决方案文件。

 

微软肯定有更好的方式去管理,但从这里可以看出,独立开发维护的优势。

 

三、接口项目准备

 

前面分享过一篇《零基础ASP.NET Core MVC插件式开发》的文章,那边文章其实也就是强调团队开发的时候能做到尽量独立,可以横向扩展,项目灵活变动增加开发人员可以快速参与,开发之后能汇总到一个个的子系统,最后完成整体开发。在这里API的开发也可以使用类似方案,因为API没有视图部分,处理起来MVC简单。

 

接下来重点介绍该方案在API开发中的使用。开始这部分内容之前先简单介绍我这边API项目开发总结的两个共性问题:

1、使用swagger显示API文档(nuget 引用 Swashbuckle.AspNetCore

因为API是没有试图的,为了可视化,以及方便测试,使用swagger作为API的展示界面。具体使用看下面提供的demo代码

 

2、使用版本控制API版本号(nuget 引用Microsoft.AspNetCore.Mvc.Versioning

版本控制对API也是同样重要,看BAT大厂提供的API都是有版本控制的,要向他们看齐。实际应用中,程序不可能维持一套最新,有时候新旧版本需要过渡,所以需要有版本来区分。这里使用微软提供的版本控制。具体使用看下面提供的demo代码

 

 

这两个使用这里就不细说了,穿插下面主题做些简单介绍,具体看案例demo就可以。

 

四、接口插件式开发

 

回到我们的主题,这里重点介绍下一个子系统(模块)任务拆分与人员分工

 

项目组接下一个项目,一般有个开发组长,着手模块划分并且开发任务分工

组长(公共部分接口+核心功能模块接口)

组员1:细分的模块插件1接口

组员2:细分的模块插件2接口

组员3:细分的模块插件3接口

......

......

 

对于的解决方案结构,具体命名自己可以根据喜好自己自定义。

 

Agile.ModuleName.API  如下图3

Agile.ModuleName.Plug1.API 图下图4

Agile.ModuleName.Plug2.API

Agile.ModuleName.Plug3.API

......

......

 

 

3

 

4

 

Demo使用的是vs2019Asp.net core 2.1

 

注意:如果一个模块里面接口比较多,一个解决方案里面不适合团队开发。所以对这种接口功能比较多,拆成各个插件方便团队开发,最后发布的时候合并到一起。但是如果这个模块接口不是很多,就没必要过度设计为了插件化而拆开。

 

每个独立开发的都是vs里面建立的标准ASP.NET Core WebAPI项目,这里主项目和各个插件项目没有从属关系,完全平等API项目开发,最后只是可以汇合到主项目作为一个站点发布交付。各自独立调试运行各自开发功能模块,测试没问题发布汇总到主项目,部署运行,之后哪个接口问题只需要找到对应的模块修改,完全隔离开,不用担心修改会影响其他正常使用的模块。

 

 

主项目解决方案结构,如图5

 

5

 

v1v2里面的是有版本控制的,放在外面的就不需要版本控制。

还有Extensions文件夹里面两个类也是为了版本的显示做处理,具体看Startup.cs里面代码,如图6

 

6

 

搭建好之后,主项目运行,选择v1版本显示如图7

 

7

 

如果选择v2,显示如图8

 

8

 

通过上面两个切换,应该看到不管选择v1还是v2下面不受版本控制的都会显示。

 

 

如果把图4的代码注释掉,看下运行效果,如图9

 

 

9

显示就这样,不能根据swagger选择,直观的显示是v1还是v2。这个就是RemoveVersionFromParameterReplaceVersionWithExactValueInPath两个类的作用。

 这两个类的代码如下

public class RemoveVersionFromParameter : IOperationFilter
    {
        public void Apply(Operation operation, OperationFilterContext context)
        {
            if (operation.Parameters.Count > 0)
            {
                var versionParameter = operation.Parameters.FirstOrDefault(p => p.Name == "version");
                operation.Parameters.Remove(versionParameter);
            }
        }
    }


public class ReplaceVersionWithExactValueInPath : IDocumentFilter
    {
        public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
        {
            swaggerDoc.Paths = swaggerDoc.Paths
                .ToDictionary(
                    path => path.Key.Replace("v{version}", swaggerDoc.Info.Version),
                    path => path.Value
                );
        }
    }

 

到这里主项目API运行正常,接下来看下插件项目API

插件1项目结构,和主项目类似,如图10

 

10

单独运行下这个插件1项目,效果如图11

 

11

 

这里作为插件API项目同样有一点要注意,不要出现和其他插件或者主项目同名的路由(versioncontrolleraction三个完全一样,分工之后各自命名规范估计这种情况也不会出现,主要还是注意避免合并之后路由重名问题)。

 

这里先把插件1编译的dll放到主项目的运行目录来,如图12

 

12

 

并且在主项目的Startup.cs里面增加这段代码,如图13

 

13

 

运行看下效果,如图14

 

14

 

汇合成功,插件1API能展示出来,测试也正常,测试就不截图了。

同理,插件1,插件2...等等也是一样处理。开发阶段,各自开发的功能都是可以独立调试运行的。有没有主项目对各自开发的不影响。

 

 

 

 

五、问题总结

 

如果插件项目里面引用了一个第三方的程序集,如图15

 

15

 

引用一个测试类库,在Plug1NoVerControllerGet方法里面写一个测试代码,如图16

 

16

在插件项目单独测试,运行正常。

再把插件1相关文件拷贝到主项目,这时候多了个插件项目自己引用的OtherLib.dll,如图17

 

17

 

正常运行,如图18

 

18

 

测试下刚才插件1里面用到OtherLib类的接口,看效果如图19

 

19

 

汗,居然报错了,提示FileNotFoundException,但是看上面的错误信息截图提示找不到OtherLib.dll文件。OtherLib.dll这个文件明明在这个目录有的。查了相关资料都说是.net core的加载机制变了,但还是没理解透彻,不知道.net core3.0会不会解决这个问题。希望有大神看到可以解惑下这个问题。不过这里我使用一种方式可以解决这个报错,在主程序这里加这段代码。在注册插件项目之前,遍历所有dll,做一次加载就可以了。如图20

 

20

 

需要在注册插件之前,把所有dll文件这样加载一遍,就可以了。

再运行,测试就正常了,如图21

 

21

 

 

六、发布运行

各个独立开发的插件API,各自独立开发调试正常之后,发布出来。

好了,插件1,插件2...等等各自都开发好了,各自模块调试没问题,最后汇总到主的项目来,基本也就没什么问题了,并且还可以作为一个站点部署。

这里的一个站点只是一个接口服务,不要理解成一个系统就这一个接口服务,虽然可以这样做,但不建议,部署还是各个子系统一个服务,这样数量也不会很多。这里是指在开发阶段对一个子系统(模块)的N个接口做开发方面的分工独立开发调试。

子系统(模块)有N个接口,开发分工如下:

主插件,插件1,插件2,插件3...

全部汇总到主插件的发布目录,或者手动拷贝,最后提供一个完成的子系统接口发布版本,目录如图22

 

22

 

同样命令行运行,或者宿主到iis,这里命令行运行,如图23

 

23

 

浏览器打开,如图24

 

24

 

直接swagger测试各个接口,正常。

独立插件化开发,微服务发布部署。

 

希望你看了之后有点收获,代码程序下面附件提供

Demo程序

posted @ 2019-07-17 07:32  村委第一书记  阅读(2747)  评论(11编辑  收藏  举报