打造本身的.NET Core项目模板

前言

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

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

可能不一样的公司对这些会有特定的要求,也可能会随开发本身的想法去实践。web

那么,问题就来了。若是有一个新项目,你会怎么去建立?sql

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

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

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

可是呢,这三种方式,始终都有不尽人意的地方。服务器

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

下面介绍一个小办法来帮你们省点时间。ide

基于dotnet cli建立本身的项目模板,也就是你们常说的脚手架。ui

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

下面是一些能够开箱即用的模板:

https://dotnetnew.azurewebsites.net/

总结

有一个本身的项目模板(脚手架),仍是很方便的。

一建生成本身须要的东西,减小了没必要要的代码复制,能够将更多精力放在业务实现上。

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

参考文档

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

最后是文中的示例代码

Template

相关文章
相关标签/搜索