1. 程式人生 > >NET Core專案模板

NET Core專案模板

打造自己的.NET Core專案模板

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

前言
每個人都有自己習慣的專案結構,有人的喜歡在專案裡面建解決方案資料夾;有的人喜歡傳統的三層命名;有的人喜歡單一,簡單的專案一個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包,我們加入下面的內容








同樣的,程式碼也要做相應的處理

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

如果您認為這篇文章還不錯或者有所收穫,可以點選右下角的【推薦】按鈕,因為你的支援是我繼續寫作,分享的最大動力!
作者:Catcher ( 黃文清 )
來源:http://catcher1994.cnblogs.com/