打造自己的.NET Core项目模板
前言
每个人都有自己习惯的项目结构,有人的喜欢在项目里面建解决方案文件夹;有的人喜欢传统的三层命名;有的人喜欢单一,简单的项目一个csproj就搞定。。
反正就是萝卜青菜,各有所爱。
可能不同的公司对这些会有特定的要求,也可能会随开发自己的想法去实践。
那么,问题就来了。如果有一个新项目,你会怎么去创建?
可能比较多的方式会是下面三种:
- 简单粗暴型,打开vs就是右键添加,然后引入一堆包,每个项目添加引用。
- 脚本型,基于dotnet cli,创建解决方案,创建项目,添加包,添加项目引用。
- 高大上型,vs项目模板,直接集成到vs上面了。
以前我也是基于dotnet cli写好了sh或ps的脚本,然后用这些脚本来生成新项目。
但是呢,这三种方式,始终都有不尽人意的地方。
因为建好的都是空模板,还要做一堆复杂的操作才可以让项目“正常”的跑起来。比如,这个公共类要抄过来,那个公共类要抄过来。。。这不是明摆着浪费时间嘛。。。
下面介绍一个小办法来帮大家省点时间。
基于dotnet cli创建自己的项目模板,也就是大家常说的脚手架。
dotnet cli项目模板预热
开始正题之前,我们先看一下dotnet cli自带的一些模板。
可以看到种类还是很多的,由于工作大部分时间都是在写webapi,所以这里就用webapi来写个简单的模板。
下面我们就基于dotnet cli写一个自己的模板。
编写自己的模板
既然是模板,就肯定会有一个样例项目。
下面我们建一个样例项目,大致成这样,大家完全可以按照自己习惯来。
这其实就是一个普通的项目,里面添加了nlog,swagger,dapper等组件,各个项目的引用关系是建好的。
该有的公共类,里面也都包含了,好比宇内分享的那个webhostbuilderjexusextensions。
下面是这个模板跑起来的效果。
就是一个简单的swagger页面。
现在样例已经有了,要怎么把这个样例变成一个模板呢?
答案就是template.json
!
在样例的根目录创建一个文件夹.template.config
,同时在这个文件夹下面创建template.json
。
示例如下:
{ "author": "catcher wong", //必须 "classifications": [ "web/webapi" ], //必须,这个对应模板的tags "name": "tpldemo", //必须,这个对应模板的templates "identity": "tpldemotemplate", //可选,模板的唯一名称 "shortname": "tpl", //必须,这个对应模板的short name "tags": { "language": "c#" , "type":"project" }, "sourcename": "tpldemo", // 可选,要替换的名字 "prefernamedirectory": true // 可选,添加目录 }
在这里,有几个比较重要的东西,一个是shortname,一个是sourcename。
- shortname,简写,偷懒必备,好比能写
-h
就绝对不写--help
- sourcename,这是个可选的字段,它的值会替换指定的项目名,正常是把项目名赋值在这里。如果不指定,创建的项目就和样例项目保持一致。
在写完template.json
之后,还需要安装一下这个模板到我们的cli中。
使用 dotnet new -i
进行模板的安装。
下面是安装示例。
dotnet new -i ./content/tpldemo
这里要注意的是,与.template.config
文件夹同级的目录,都会被打包进模板中。
在执行安装命令之后,就可以看到我们的模板已经安装好了。
这个时候已经迫不及待的想来试试这个模板了。
先来看看这个模板的帮助信息。
dotnet new tpl -h
因为我们目前还没有设置参数,所以这里显示的是还没有参数。
下面来创建一个项目试试。
从创建一个项目,到运行起来,很简单,效果也是我们预期的。
下面来看看,新建的这个hellotpl这个项目的目录结构和我们的模板是否一样。
可以看到,除了名字,其他的内容都是一样的。
是不是感觉又可以少复制粘贴好多代码了。
虽说,现在建项目,已经能把一个大的模板完整的copy出来了,但是始终不是很灵活!
可能有小伙伴会问,明明已经很方便了呀,为什么还会说它不灵活呢?
且听我慢慢道来。
如果说这个模板是个大而全的模板,包含了中间件a,中间件b,中间件c等n个中间件!
而在建新项目的时候,已经明确了只用中间件a,那么其他的中间件对我们来说,可能就没有太大的存在意义!
很多时候,不会想让这些多余的文件出现在代码中,有没有办法来控制呢?
答案是肯定的!可以把不需要的文件排除掉就可以了。
文件过滤
模板项目中有一个requestlogmiddleware
,就用它来做例子。
我们只需要做下面几件事就可以了。
第一步,在template.json
中添加过滤
加入一个名字为enablerequestlog
的symbol。同时指定源文件
{ "author": "catcher wong", //others... "symbols":{ //是否启用requestlog这个middleware "enablerequestlog": { "type": "parameter", //它是参数 "datatype":"bool", //bool类型的参数 "defaultvalue": "false" //默认是不启用 } }, "sources": [ { "modifiers": [ { "condition": "(!enablerequestlog)", //条件,由enablerequestlog参数决定 "exclude": [ //排除下面的文件 "src/tpldemo/middlewares/requestlogmiddleware.cs", "src/tpldemo/middlewares/requestlogservicecollectionextensions.cs" ] } ] } ] }
第二步,在模板的代码中做一下处理
主要是startup.cs
,因为middleware就是在这里启用的。
using system; //other using... using tpldemo.core; #if (enablerequestlog) using tpldemo.middlewares; #endif /// <summary> /// /// </summary> public class startup { public void configure(iapplicationbuilder app, ihostingenvironment env) { //other code.... #if (enablerequestlog) //request log app.userequestlog(); #endif app.usemvc(routes => { routes.maproute( name: "default", template: "{controller=home}/{action=index}/{id?}"); }); } }
这样的话,只要enablerequestlog
是true,那么就可以包含这两段代码了。
下面更新一下已经安装的模板。
这个时候再去看它的帮助信息,已经可以看到我们加的参数了。
下面先建一个默认的(不启用requestlog)
dotnet new tpl -n nolog
这个命令等价于
dotnet new tpl -n withlog -e false
下面是建好之后的目录结构和startup.cs
可以看到requestlog相关的东西都已经不见了。
再建一个启用requestlog的,看看是不是真的起作用了。
dotnet new tpl -n withlog -e true
可以看到,效果已经出来了。
下面在介绍一个比较有用的特性。动态切换,这个其实和上面介绍的内容相似。
动态切换
直接举个例子来说明吧。
假设我们的模板支持mssql, mysql, pgsql和sqlite四种数据库操作
在新建一个项目的时候,只需要其中一种,好比说要建一个pgsql的,肯定就不想看到其他三种。
这里不想看到,有两个地方,一个是nuget包的引用,一个是代码。
上一小节是对某个具体的功能进行了开关的操作,这里有了4个,我们要怎么处理呢?
我们可以用类型是choice
的参数来完成这个操作。
修改template.json
,加入下面的内容
{ "author": "catcher wong", //others "symbols":{ "sqltype": { "type": "parameter", "datatype": "choice", "choices": [ { "choice": "mssql", "description": "ms sql server" }, { "choice": "mysql", "description": "mysql" }, { "choice": "pgsql", "description": "postgresql" }, { "choice": "sqlite", "description": "sqlite" } ], "defaultvalue": "mssql", "description": "the type of sql to use" }, "mssql": { "type": "computed", "value": "(sqltype == \"mssql\")" }, "mysql": { "type": "computed", "value": "(sqltype == \"mysql\")" }, "pgsql": { "type": "computed", "value": "(sqltype == \"pgsql\")" }, "sqlite": { "type": "computed", "value": "(sqltype == \"sqlite\")" } } }
看了上面的json内容之后,相信大家也知道个所以然了。有一个名为sqltype的参数,它有几中数据库选择,默认是mssql。
还另外定义了几个计算型的参数,它的取值是和sqltype的值息息相关的。
mssql,mysql,pgsql和sqlite这4个参数也是我们在代码里要用到的!!
修改csproj文件,让它可以根据sqltype来动态引用nuget包,我们加入下面的内容
<itemgroup condition="'$(mysql)' == 'true' "> <packagereference include="mysqlconnector" version="0.47.1" /> </itemgroup> <itemgroup condition="'$(pgsql)' == 'true' "> <packagereference include="npgsql" version="4.0.3" /> </itemgroup> <itemgroup condition="'$(sqlite)' == 'true' "> <packagereference include="microsoft.data.sqlite" version="2.1.0" /> </itemgroup>
同样的,代码也要做相应的处理
#if (mssql) using system.data.sqlclient; #elif (mysql) using mysql.data.mysqlclient; #elif (pgsql) using npgsql; #else using microsoft.data.sqlite; #endif protected dbconnection getdbconnection() { #if (mssql) return new sqlconnection(_connstr); #elif (mysql) return new mysqlconnection(_connstr); #elif (pgsql) return new npgsqlconnection(_connstr); #else return new sqliteconnection(_connstr); #endif }
修改好之后,同样要去重新安装这个模板,安装好之后,就可以看到sqltype这个参数了。
下面分别创建一个mssql和pgsql的项目,用来对比和验证。
先后执行
dotnet new tpl -n mssqltest -s mssql dotnet new tpl -n pgsqltest -s pgsql
然后打开对应的csproj
可以看到,pgsql的,添加多了npgsql
这个包。而mssql的却没有。
同样的,dapperrepositorybase也是一样的效果。在创建connection对象的时候,都根据模板来生成了。
当然这个是在我们自己本地安装的模板,其他人是没有办法使用的。
如果想公开,可以发布到nuget上面去。如果是在公司内部共享,可以搭建一个内部的nuget服务,将模板上传到内部服务器里面去。
下面是一些可以开箱即用的模板:
总结
有一个自己的项目模板(脚手架),还是很方便的。
一建生成自己需要的东西,减少了不必要的代码复制,可以将更多精力放在业务实现上。
在平时还是要有一些积累,当积累足够丰富之后,我们的脚手架可能就会变得十分强大。
参考文档
dotnet new下面默认的模板 https://github.com/aspnet/templating
templating的源码
template.json的说明 https://github.com/dotnet/templating/wiki/reference-for-template.json
dotnet cli的文档
最后是文中的示例代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读
-
.Net Core库类项目跨项目读取配置文件的方法
-
打造自己的.NET Core项目模板
-
【从零开始搭建自己的.NET Core Api框架】(三)集成轻量级ORM——SqlSugar:3.3 自动生成实体类
-
建议收藏备用:.net core使用QRCoder生成普通二维码和带Logo的二维码详细使用教程,源码已更新至开源模板
-
我来告诉你:VS2019开发ASP.NET Core 3.0 Web项目,修改视图后,刷新浏览器看不到修改后的效果怎么处理
-
asp.net core 一个中小型项目实战的起手式——Swagger配置
-
创建基于ASP.NET core 3.1 的RazorPagesMovie项目(一)-创建和使用默认的模板
-
创建基于ASP.NET core 3.1 的RazorPagesMovie项目(三)-已搭建基架的Razor页面解释和更新
-
NET Framework项目移植到NET Core上遇到的一系列坑(2)
-
在 ASP.NET Core 项目中使用 npm 管理你的前端组件包