打造自己的.NET Core项目模板

打造自己的.NET Core项目模板,第1张

概述前言每个人都有自己习惯的项目结构,有人的喜欢在项目里面建解决方案文件夹;有的人喜欢传统的三层命名;有的人喜欢单一,简单的项目一个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 就绝对不写 --helpsourceName,这是个可选的字段,它的值会替换指定的项目名,正常是把项目名赋值在这里。如果不指定,创建的项目就和样例项目保持一致。在写完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 Logapp.UseRequestLog();#endifapp.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' "

<h2 ID="前言">前言

每个人都有自己习惯的项目结构,有人的喜欢在项目里面建解决方案文件夹;有的人喜欢传统的三层命名;有的人喜欢单一,简单的项目一个csproj就搞定。。

反正就是萝卜青菜,各有所爱。

可能不同的公司对这些会有特定的要求,也可能会随开发自己的想法去实践。

那么,问题就来了。如果有一个新项目,你会怎么去创建?

可能比较多的方式会是下面三种:

简单粗暴型,打开VS就是右键添加,然后引入一堆包,每个项目添加引用。脚本型,基于dotnet cli,创建解决方案,创建项目,添加包,添加项目引用。高大上型,VS项目模板,直接集成到VS上面了。

以前我也是基于dotnet cli写好了sh或ps的脚本,然后用这些脚本来生成新项目。

但是呢,这三种方式,始终都有不尽人意的地方。

因为建好的都是空模板,还要做一堆复杂的 *** 作才可以让项目“正常”的跑起来。比如,这个公共类要抄过来,那个公共类要抄过来。。。这不是明摆着浪费时间嘛。。。

下面介绍一个小办法来帮大家省点时间。

基于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 就绝对不写 --helpsourcename,这是个可选的字段,它的值会替换指定的项目名,正常是把项目名赋值在这里。如果不指定,创建的项目就和样例项目保持一致。

在写完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>pub<a href="https://m.jb51.cc/tag/li/" target="_blank" >li</a>c class Startup{    pub<a href="https://m.jb51.cc/tag/li/" target="_blank" >li</a>c vo<a href="https://m.jb51.cc/tag/ID/" target="_blank" >ID</a> Con<a href="https://www.jb51.cc/tag/fig/" target="_blank" >fig</a>ure(IApp<a href="https://m.jb51.cc/tag/li/" target="_blank" >li</a>cationBuilder app,IHostingEnvironment env)    {        //other code....
if (EnableRequestLog)
        //request Log        app.UseRequestLog();
endif
        app.UseMvc(routes =>        {            routes.MapRoute(                <a href="https://m.jb51.cc/tag/name/" target="_blank" >name</a>: "defa<a href="https://m.jb51.cc/tag/ul/" target="_blank" >ul</a>t",template: "{contr<a href="https://m.jb51.cc/tag/ol/" target="_blank" >ol</a>ler=Home}/{action=Index}/{<a href="https://m.jb51.cc/tag/ID/" target="_blank" >ID</a>?}");        });    }}</code></pre>

这样的话,只要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,Pgsql和sqlite这4个参数也是我们在代码里要用到的!!

修改csproj文件,让它可以根据sqlType来动态引用nuget包,我们加入下面的内容

<ItemGroup Condition="'$(Pgsql)' == 'True' ">

<ItemGroup Condition="'$(sqlite)' == 'True' ">

同样的,代码也要做相应的处理

#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 <a href="https://www.jb51.cc/tag/sql/" target="_blank" >sql</a>Connection(_connStr);
elif (MysqL)
    return new <a href="https://www.jb51.cc/tag/MysqL/" target="_blank" >MysqL</a>Connection(_connStr);
elif (Pgsql)
    return new Npg<a href="https://www.jb51.cc/tag/sql/" target="_blank" >sql</a>Connection(_connStr);
else
    return new <a href="https://www.jb51.cc/tag/sql/" target="_blank" >sql</a>iteConnection(_connStr);
endif
}</code></pre>

修改好之后,同样要去重新安装这个模板,安装好之后,就可以看到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下面默认的模板

templating的源码

template.json的说明

dotnet cli的文档

最后是文中的示例代码

总结

以上是内存溢出为你收集整理的打造自己的.NET Core项目模板全部内容,希望文章能够帮你解决打造自己的.NET Core项目模板所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/langs/1256045.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存