1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        打造自己的.NET Core項(xiàng)目模板

        共 6885字,需瀏覽 14分鐘

         ·

        2021-01-13 22:06

        1.前言

        每個(gè)人都有自己習(xí)慣的項(xiàng)目結(jié)構(gòu),有人的喜歡在項(xiàng)目里面建解決方案文件夾;有的人喜歡傳統(tǒng)的三層命名;有的人喜歡單一,簡單的項(xiàng)目一個(gè)csproj就搞定。。

        反正就是蘿卜青菜,各有所愛。

        可能不同的公司對(duì)這些會(huì)有特定的要求,也可能會(huì)隨開發(fā)自己的想法去實(shí)踐。

        那么,問題就來了。如果有一個(gè)新項(xiàng)目,你會(huì)怎么去創(chuàng)建?

        可能比較多的方式會(huì)是下面三種:

        • 簡單粗暴型,打開VS就是右鍵添加,然后引入一堆包,每個(gè)項(xiàng)目添加引用。
        • 腳本型,基于dotnet cli,創(chuàng)建解決方案,創(chuàng)建項(xiàng)目,添加包,添加項(xiàng)目引用。
        • 高大上型,VS項(xiàng)目模板,直接集成到VS上面了。以前我也是基于dotnet cli寫好了sh或ps的腳本,然后用這些腳本來生成新項(xiàng)目。

        但是呢,這三種方式,始終都有不盡人意的地方。

        因?yàn)榻ê玫亩际强漳0?,還要做一堆復(fù)雜的操作才可以讓項(xiàng)目“正?!钡呐芷饋怼1热?,這個(gè)公共類要抄過來,那個(gè)公共類要抄過來。。。這不是明擺著浪費(fèi)時(shí)間嘛。。。

        下面介紹一個(gè)小辦法來幫大家省點(diǎn)時(shí)間。

        基于dotnet cli創(chuàng)建自己的項(xiàng)目模板,也就是大家常說的腳手架。

        2.dotnet cli項(xiàng)目模板預(yù)熱

        開始正題之前,我們先看一下dotnet cli自帶的一些模板。

        可以看到種類還是很多的,由于工作大部分時(shí)間都是在寫WebAPI,所以這里就用WebAPI來寫個(gè)簡單的模板。

        下面我們就基于dotnet cli寫一個(gè)自己的模板。

        3.編寫自己的模板

        既然是模板,就肯定會(huì)有一個(gè)樣例項(xiàng)目。

        下面我們建一個(gè)樣例項(xiàng)目,大致成這樣,大家完全可以按照自己習(xí)慣來。

        這其實(shí)就是一個(gè)普通的項(xiàng)目,里面添加了NLog,Swagger,Dapper等組件,各個(gè)項(xiàng)目的引用關(guān)系是建好的。

        該有的公共類,里面也都包含了,好比宇內(nèi)分享的那個(gè)WebHostBuilderJexusExtensions。

        下面是這個(gè)模板跑起來的效果。

        就是一個(gè)簡單的Swagger頁面。

        現(xiàn)在樣例已經(jīng)有了,要怎么把這個(gè)樣例變成一個(gè)模板呢?

        答案就是template.json

        在樣例的根目錄創(chuàng)建一個(gè)文件夾.template.config,同時(shí)在這個(gè)文件夾下面創(chuàng)建template.json。

        示例如下:

        {
        ????"author":?"Catcher?Wong",?//必須
        ????"classifications":?[?"Web/WebAPI"?],?//必須,這個(gè)對(duì)應(yīng)模板的Tags
        ????"name":?"TplDemo",?//必須,這個(gè)對(duì)應(yīng)模板的Templates
        ????"identity":?"TplDemoTemplate",?//可選,模板的唯一名稱
        ????"shortName":?"tpl",?//必須,這個(gè)對(duì)應(yīng)模板的Short?Name
        ????"tags":?{
        ??????"language":?"C#"?,
        ??????"type":"project"
        ????},
        ????"sourceName":?"TplDemo",??//?可選,要替換的名字
        ????"preferNameDirectory":?true??//?可選,添加目錄??
        }

        在這里,有幾個(gè)比較重要的東西,一個(gè)是shortName,一個(gè)是sourceName。

        • shortName,簡寫,偷懶必備,好比能寫 -h 就絕對(duì)不寫 ``--help`
        • sourceName,這是個(gè)可選的字段,它的值會(huì)替換指定的項(xiàng)目名,正常是把項(xiàng)目名賦值在這里。如果不指定,創(chuàng)建的項(xiàng)目就和樣例項(xiàng)目保持一致。在寫完template.json之后,還需要安裝一下這個(gè)模板到我們的cli中。

        使用 dotnet new -i進(jìn)行模板的安裝。

        下面是安裝示例:

        dotnet?new?-i?./content/TplDemo

        這里要注意的是,與.template.config文件夾同級(jí)的目錄,都會(huì)被打包進(jìn)模板中。在執(zhí)行安裝命令之后,就可以看到我們的模板已經(jīng)安裝好了。

        這個(gè)時(shí)候已經(jīng)迫不及待的想來試試這個(gè)模板了。

        先來看看這個(gè)模板的幫助信息。

        dotnet?new?tpl?-h

        因?yàn)槲覀兡壳斑€沒有設(shè)置參數(shù),所以這里顯示的是還沒有參數(shù)。

        下面來創(chuàng)建一個(gè)項(xiàng)目試試。

        從創(chuàng)建一個(gè)項(xiàng)目,到運(yùn)行起來,很簡單,效果也是我們預(yù)期的。

        下面來看看,新建的這個(gè)HelloTpl這個(gè)項(xiàng)目的目錄結(jié)構(gòu)和我們的模板是否一樣。

        可以看到,除了名字,其他的內(nèi)容都是一樣的。

        是不是感覺又可以少復(fù)制粘貼好多代碼了。

        雖說,現(xiàn)在建項(xiàng)目,已經(jīng)能把一個(gè)大的模板完整的copy出來了,但是始終不是很靈活!

        可能有小伙伴會(huì)問,明明已經(jīng)很方便了呀,為什么還會(huì)說它不靈活呢?

        且聽我慢慢道來。

        如果說這個(gè)模板是個(gè)大而全的模板,包含了中間件A,中間件B,中間件C等N個(gè)中間件!

        而在建新項(xiàng)目的時(shí)候,已經(jīng)明確了只用中間件A,那么其他的中間件對(duì)我們來說,可能就沒有太大的存在意義!

        很多時(shí)候,不會(huì)想讓這些多余的文件出現(xiàn)在代碼中,有沒有辦法來控制呢?

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

        4.文件過濾

        模板項(xiàng)目中有一個(gè)RequestLogMiddleware,就用它來做例子。

        我們只需要做下面幾件事就可以了。

        第一步,在template.json中添加過濾

        加入一個(gè)名字為EnableRequestLogsymbol。同時(shí)指定源文件

        {
        ????"author":?"Catcher?Wong",
        ????//others...
        ????"symbols":{
        ??????//是否啟用RequestLog這個(gè)Middleware
        ??????"EnableRequestLog":?{
        ????????"type":?"parameter",?//它是參數(shù)
        ????????"dataType":"bool",?//bool類型的參數(shù)
        ????????"defaultValue":?"false"?//默認(rèn)是不啟用
        ??????}
        ????},
        ????"sources":?[
        ??????{
        ??????????"modifiers":?[
        ??????????????{
        ??????????????????"condition":?"(!EnableRequestLog)",?//條件,由EnableRequestLog參數(shù)決定
        ??????????????????"exclude":?[?//排除下面的文件
        ????????????????????"src/TplDemo/Middlewares/RequestLogMiddleware.cs",
        ????????????????????"src/TplDemo/Middlewares/RequestLogServiceCollectionExtensions.cs"?
        ??????????????????]
        ??????????????}
        ??????????]
        ??????}
        ????]????
        ??}

        第二步,在模板的代碼中做一下處理

        主要是Startup.cs,因?yàn)镸iddleware就是在這里啟用的。

        ????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,那么就可以包含這兩段代碼了。

        下面更新一下已經(jīng)安裝的模板。

        這個(gè)時(shí)候再去看它的幫助信息,已經(jīng)可以看到我們加的參數(shù)了。

        下面先建一個(gè)默認(rèn)的(不啟用RequestLog)

        dotnet?new?tpl?-n?NoLog

        這個(gè)命令等價(jià)于

        dotnet?new?tpl?-n?WithLog?-E?false

        下面是建好之后的目錄結(jié)構(gòu)和Startup.cs

        可以看到RequestLog相關(guān)的東西都已經(jīng)不見了。

        再建一個(gè)啟用RequestLog的,看看是不是真的起作用了。

        dotnet?new?tpl?-n?WithLog?-E?true

        可以看到,效果已經(jīng)出來了。

        下面在介紹一個(gè)比較有用的特性。動(dòng)態(tài)切換,這個(gè)其實(shí)和上面介紹的內(nèi)容相似。

        5.動(dòng)態(tài)切換

        直接舉個(gè)例子來說明吧。

        假設(shè)我們的模板支持MSSQL, MySQL, PgSQL和SQLite四種數(shù)據(jù)庫操作

        在新建一個(gè)項(xiàng)目的時(shí)候,只需要其中一種,好比說要建一個(gè)PgSQL的,肯定就不想看到其他三種。

        這里不想看到,有兩個(gè)地方,一個(gè)是nuget包的引用,一個(gè)是代碼。

        上一小節(jié)是對(duì)某個(gè)具體的功能進(jìn)行了開關(guān)的操作,這里有了4個(gè),我們要怎么處理呢?

        我們可以用類型是choice的參數(shù)來完成這個(gè)操作。

        修改template.json,加入下面的內(nèi)容

        {
        ??"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內(nèi)容之后,相信大家也知道個(gè)所以然了。有一個(gè)名為sqlType的參數(shù),它有幾中數(shù)據(jù)庫選擇,默認(rèn)是MsSQL。

        還另外定義了幾個(gè)計(jì)算型的參數(shù),它的取值是和sqlType的值息息相關(guān)的。

        MsSQL,MySQL,PgSQL和SQLite這4個(gè)參數(shù)也是我們?cè)诖a里要用到的?。?/p>

        修改csproj文件,讓它可以根據(jù)sqlType來動(dòng)態(tài)引用nuget包,我們加入下面的內(nèi)容

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


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


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

        同樣的,代碼也要做相應(yīng)的處理

        #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??????????????
        ????}

        修改好之后,同樣要去重新安裝這個(gè)模板,安裝好之后,就可以看到sqlType這個(gè)參數(shù)了。

        下面分別創(chuàng)建一個(gè)MsSQL和PgSQL的項(xiàng)目,用來對(duì)比和驗(yàn)證。

        先后執(zhí)行

        dotnet?new?tpl?-n?MsSQLTest?-s?MsSQL?
        dotnet?new?tpl?-n?PgSQLTest?-s?PgSQL

        然后打開對(duì)應(yīng)的csproj

        可以看到,PgSQL的,添加多了NPgsql這個(gè)包。而MsSQL的卻沒有。

        同樣的,DapperRepositoryBase也是一樣的效果。在創(chuàng)建Connection對(duì)象的時(shí)候,都根據(jù)模板來生成了。

        當(dāng)然這個(gè)是在我們自己本地安裝的模板,其他人是沒有辦法使用的。

        如果想公開,可以發(fā)布到nuget上面去。如果是在公司內(nèi)部共享,可以搭建一個(gè)內(nèi)部的nuget服務(wù),將模板上傳到內(nèi)部服務(wù)器里面去。

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

        https://dotnetnew.azurewebsites.net/

        6. 總結(jié)

        有一個(gè)自己的項(xiàng)目模板(腳手架),還是很方便的。

        一建生成自己需要的東西,減少了不必要的代碼復(fù)制,可以將更多精力放在業(yè)務(wù)實(shí)現(xiàn)上。

        在平時(shí)還是要有一些積累,當(dāng)積累足夠豐富之后,我們的腳手架可能就會(huì)變得十分強(qiáng)大。

        參考文檔:

        dotnet new下面默認(rèn)的模板 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







        回復(fù)?【關(guān)閉】學(xué)關(guān)
        回復(fù)?【實(shí)戰(zhàn)】獲取20套實(shí)戰(zhàn)源碼
        回復(fù)?【被刪】學(xué)個(gè)
        回復(fù)?【訪客】學(xué)
        回復(fù)?【小程序】學(xué)獲取15套【入門+實(shí)戰(zhàn)+賺錢】小程序源碼
        回復(fù)?【python】學(xué)微獲取全套0基礎(chǔ)Python知識(shí)手冊(cè)
        回復(fù)?【2019】獲取2019 .NET 開發(fā)者峰會(huì)資料PPT
        回復(fù)?【加群】加入dotnet微信交流群

        副業(yè)剛需,沒有人能拒絕這個(gè)網(wǎng)站!


        終于GitHub App 已支持簡體中文!




        瀏覽 33
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            熟女人妻在线观看 | www.91自拍.com | 国产精品男人天堂 | av无码aV天天aV天天爽 | 中文字幕无码一区二区三区一本久道不卡 | 婷婷六月天 | 国产99久久久国产精品免费高清 | 日韩免费视频一区三区 | 自拍青青在线视频 | 韩国vip内部大尺度青草 |