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

共 6885字,需浏览 14分钟

 ·

2021-01-13 22:06

1.前言

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

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

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

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

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

  • 简单粗暴型,打开VS就是右键添加,然后引入一堆包,每个项目添加引用。
  • 脚本型,基于dotnet cli,创建解决方案,创建项目,添加包,添加项目引用。
  • 高大上型,VS项目模板,直接集成到VS上面了。以前我也是基于dotnet cli写好了sh或ps的脚本,然后用这些脚本来生成新项目。

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

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

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

基于dotnet cli创建自己的项目模板,也就是大家常说的脚手架。

2.dotnet cli项目模板预热

开始正题之前,我们先看一下dotnet cli自带的一些模板。

可以看到种类还是很多的,由于工作大部分时间都是在写WebAPI,所以这里就用WebAPI来写个简单的模板。

下面我们就基于dotnet cli写一个自己的模板。

3.编写自己的模板

既然是模板,就肯定会有一个样例项目。

下面我们建一个样例项目,大致成这样,大家完全可以按照自己习惯来。

这其实就是一个普通的项目,里面添加了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,那么其他的中间件对我们来说,可能就没有太大的存在意义!

很多时候,不会想让这些多余的文件出现在代码中,有没有办法来控制呢?

答案是肯定的!可以把不需要的文件排除掉就可以了。

4.文件过滤

模板项目中有一个RequestLogMiddleware,就用它来做例子。

我们只需要做下面几件事就可以了。

第一步,在template.json中添加过滤

加入一个名字为EnableRequestLogsymbol。同时指定源文件

{
    "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

    /// 
    /// 
    /// 

    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

可以看到,效果已经出来了。

下面在介绍一个比较有用的特性。动态切换,这个其实和上面介绍的内容相似。

5.动态切换

直接举个例子来说明吧。

假设我们的模板支持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包,我们加入下面的内容

"'$(MySQL)' == 'True' ">  
    "MySqlConnector" Version="0.47.1" />


"'$(PgSQL)' == 'True' ">  
    "Npgsql" Version="4.0.3" />


"'$(SQLite)' == 'True' ">  
    "Microsoft.Data.Sqlite" Version="2.1.0" />

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

#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服务,将模板上传到内部服务器里面去。

下面是一些可以开箱即用的模板:

https://dotnetnew.azurewebsites.net/

6. 总结

有一个自己的项目模板(脚手架),还是很方便的。

一建生成自己需要的东西,减少了不必要的代码复制,可以将更多精力放在业务实现上。

在平时还是要有一些积累,当积累足够丰富之后,我们的脚手架可能就会变得十分强大。

参考文档:

dotnet new下面默认的模板 https://github.com/aspnet/Templating

templating的源码 https://github.com/dotnet/templating

template.json的说明 https://github.com/dotnet/templating/wiki/Reference-for-template.json

dotnet cli的文档 https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet?tabs=netcore21

最后是文中的示例代码:https://github.com/catcherwong/Demos/tree/master/src/Template

原文:https://www.cnblogs.com/catcher1994/p/10061470.html







回复 【关闭】广
回复 【实战】获取20套实战源码
回复 【被删】
回复 【访客】访
回复 【小程序】学获取15套【入门+实战+赚钱】小程序源码
回复 【python】学微获取全套0基础Python知识手册
回复 【2019】获取2019 .NET 开发者峰会资料PPT
回复 【加群】加入dotnet微信交流群

副业刚需,没有人能拒绝这个网站!


终于GitHub App 已支持简体中文!




浏览 13
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报