一、文件夹\项目结构

1.1、文件夹

net6.0:针对.net 6.0 项目模板

net6.0pack:针对net6.0打包

1.2、项目结构

Web\WebApi多项目、各层项目、单元测试项目

目标:制作Web\WebApi两个项目模板

二、模板参数

2.1、template\net6.0\.template.config\template.json

{
"$schema": "http://json.schemastore.org/template",
"author": "yinyunpan",
"classifications": [ "Web", "WebApi" ],
"name": "项目模板案例",
"identity": "sample.template",
"shortName": "st",
"tags": {
"language": "C#",
//解决方案,与HostIdentifier用法生成解决方案文件名呼应
"type": "solution"
},
"sourceName": "sampletemplate",
"preferNameDirectory": false,
//重新生成项目guid,对应template.sln中项目guid
"guids": [
"5A6E6B9F-F8FA-4152-95B4-860F8CCAE3C3",
"30B12CFC-11E1-4E1C-B484-F708CEBD080A",
"810CD02B-0E13-4123-A84F-FBD4F4F1CD3A",
"3D2A540B-E773-44FA-82CF-14F3393D41B2",
"F4C1EFA8-824C-4985-A50D-BD1171ED1CFC",
"41C74675-6234-41F2-9B8A-4D06159D2A81",
"5EAD3BC3-554B-4058-9A9D-A91DF5F2DE1C",
"8A522BE9-0EE5-4C54-861B-394452A6744E",
"F075845E-43F4-466D-B731-904782BD9047"
],
"symbols": {
/**
template.sln文件有用host,排除项目文件引用
modifiers-condition,排除文件夹+文件
**/
"host": {
"type": "parameter",
"datatype": "choice",
"choices": [
{
"choice": "web",
"description": "后台"
},
{
"choice": "webapi",
"description": "接口"
}
],
"defaultValue": "web",
"description": "项目类型",
"displayName": "项目类型",
"isRequired": true
},
"web": {
"type": "computed",
"value": "(host == \"web\")"
},
"webapi": {
"type": "computed",
"value": "(host == \"webapi\")"
},
//应用的环境变量
"appUK": {
"type": "parameter",
"datatype": "string",
"description": "应用标识",
"displayName": "应用标识",
"isRequired": true,
"replaces": "wutong.netcore.sampletemplate"
},
"kestrelHttpPort": {
"type": "parameter",
"datatype": "integer",
"description": "启动配置文件的http端口",
"displayName": "http端口"
},
"kestrelHttpPortGenerated": {
"type": "generated",
"generator": "port",
"parameters": {
"low": 5000,
"high": 5300
}
},
"kestrelHttpPortReplacer": {
"type": "generated",
"generator": "coalesce",
"parameters": {
"sourceVariableName": "kestrelHttpPort",
"fallbackVariableName": "kestrelHttpPortGenerated"
},
//与launchSettings.json端口一致,才能随机生成替换
"replaces": "5000"
},
//模板主机标识
"HostIdentifier": {
"type": "bind",
"binding": "HostIdentifier"
}
},
"sources": [
{
"exclude": [ ".template.config/**/*", ".vs/**/*" ],
"modifiers": [
{
"condition": "(web)",
"exclude": [ "src/WebApi/**/*", "test/WebApiUnitTest/**/*" ]
},
{
"condition": "(webapi)",
"exclude": [ "src/Web/**/*", "test/WebUnitTest/**/*" ]
},
{
/**
visual studio创建模板会自动生成新的解决方案文件.sln、与模板下{sourceName}.sln冲突,导致生成visual studio提醒外部文件变化重新加载,操作不友好
判断使用模板主机标识:vs-visual studio、dotnetcli\dotnetcli-preview-命令窗口
模板下解决方案文件名要非{sourceName}.sln,命令窗口重命名
参考:https://github.com/sayedihashimi/template-sample/tree/main/src/Samples/06-console-csharp-fsharp
**/
"condition": "(HostIdentifier == \"dotnetcli\" || HostIdentifier == \"dotnetcli-preview\")",
"rename": {
"template.sln": "sampletemplate.sln"
}
}
]
}
]
}

总结:

  host定义项目类型,方便使用在host基础上定义web、webapi计算型布尔变量。

  项目开发中本地启动文件(launchSettings.json)中会经常用环境变量,如:应用标识。

  模板文件中关键字替换依赖环境变量的replaces参数,需要注意保证replaces的值与文件被替换的值一样,如:http端口、应用标识。

  根据项目类型,排除web\webapi对应的项目以及单元测试项目文件。

  如果需要区分当前使用模板场景(visual studio 可视化窗口、命令行窗口),有不同执行行为,可以使用HostIdentifier变量。如:解决文件.sln生成。

  

2.2、template\net6.0\.template.config\ide.host.json

{
"$schema": "http://json.schemastore.org/vs-2017.3.host",
"order": 200,
"icon": "ide/sampletemplate.png",
"symbolInfo": [
{
"id": "host",
"isVisible": true
},
{
"id": "appUK",
"isVisible": true
},
//隐藏http端口,自动生成
{
"id": "kestrelHttpPort",
"isVisible": false
}
]
}

2.3、template\net6.0\.template.config\dotnetcli.host.json

{
"$schema": "http://json.schemastore.org/dotnetcli.host",
"symbolInfo": {
"host": {
"isHidden": false
},
"appUK": {
"isHidden": false
},
//隐藏http端口,自动生成
"kestrelHttpPort": {
"isHidden": true
}
}
}

三、解决方案文件设置


Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32414.318
MinimumVisualStudioVersion = 10.0.40219.1
<!--#if(web)-->
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "src\Web\Web.csproj", "{F075845E-43F4-466D-B731-904782BD9047}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebUnitTest", "test\WebUnitTest\WebUnitTest.csproj", "{8A522BE9-0EE5-4C54-861B-394452A6744E}"
EndProject
<!--#endif-->
<!--#if(webapi)-->
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApi", "src\WebApi\WebApi.csproj", "{5A6E6B9F-F8FA-4152-95B4-860F8CCAE3C3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApiUnitTest", "test\WebApiUnitTest\WebApiUnitTest.csproj", "{5EAD3BC3-554B-4058-9A9D-A91DF5F2DE1C}"
EndProject
<!--#endif-->
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shared", "src\Shared\Shared.csproj", "{30B12CFC-11E1-4E1C-B484-F708CEBD080A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Domain.Interfaces", "src\Domain.Interfaces\Domain.Interfaces.csproj", "{810CD02B-0E13-4123-A84F-FBD4F4F1CD3A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Domain.Service", "src\Domain.Service\Domain.Service.csproj", "{3D2A540B-E773-44FA-82CF-14F3393D41B2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure.Interfaces", "src\Infrastructure.Interfaces\Infrastructure.Interfaces.csproj", "{F4C1EFA8-824C-4985-A50D-BD1171ED1CFC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure.Implements", "src\Infrastructure.Implements\Infrastructure.Implements.csproj", "{41C74675-6234-41F2-9B8A-4D06159D2A81}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
<!--#if(web)-->
{F075845E-43F4-466D-B731-904782BD9047}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F075845E-43F4-466D-B731-904782BD9047}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F075845E-43F4-466D-B731-904782BD9047}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F075845E-43F4-466D-B731-904782BD9047}.Release|Any CPU.Build.0 = Release|Any CPU
{8A522BE9-0EE5-4C54-861B-394452A6744E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A522BE9-0EE5-4C54-861B-394452A6744E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A522BE9-0EE5-4C54-861B-394452A6744E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A522BE9-0EE5-4C54-861B-394452A6744E}.Release|Any CPU.Build.0 = Release|Any CPU
<!--#endif-->
<!--#if(webapi)-->
{5A6E6B9F-F8FA-4152-95B4-860F8CCAE3C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5A6E6B9F-F8FA-4152-95B4-860F8CCAE3C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5A6E6B9F-F8FA-4152-95B4-860F8CCAE3C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A6E6B9F-F8FA-4152-95B4-860F8CCAE3C3}.Release|Any CPU.Build.0 = Release|Any CPU
{5EAD3BC3-554B-4058-9A9D-A91DF5F2DE1C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5EAD3BC3-554B-4058-9A9D-A91DF5F2DE1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5EAD3BC3-554B-4058-9A9D-A91DF5F2DE1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5EAD3BC3-554B-4058-9A9D-A91DF5F2DE1C}.Release|Any CPU.Build.0 = Release|Any CPU
<!--#endif-->
{30B12CFC-11E1-4E1C-B484-F708CEBD080A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{30B12CFC-11E1-4E1C-B484-F708CEBD080A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30B12CFC-11E1-4E1C-B484-F708CEBD080A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{30B12CFC-11E1-4E1C-B484-F708CEBD080A}.Release|Any CPU.Build.0 = Release|Any CPU
{810CD02B-0E13-4123-A84F-FBD4F4F1CD3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{810CD02B-0E13-4123-A84F-FBD4F4F1CD3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{810CD02B-0E13-4123-A84F-FBD4F4F1CD3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{810CD02B-0E13-4123-A84F-FBD4F4F1CD3A}.Release|Any CPU.Build.0 = Release|Any CPU
{3D2A540B-E773-44FA-82CF-14F3393D41B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3D2A540B-E773-44FA-82CF-14F3393D41B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D2A540B-E773-44FA-82CF-14F3393D41B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D2A540B-E773-44FA-82CF-14F3393D41B2}.Release|Any CPU.Build.0 = Release|Any CPU
{F4C1EFA8-824C-4985-A50D-BD1171ED1CFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F4C1EFA8-824C-4985-A50D-BD1171ED1CFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F4C1EFA8-824C-4985-A50D-BD1171ED1CFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F4C1EFA8-824C-4985-A50D-BD1171ED1CFC}.Release|Any CPU.Build.0 = Release|Any CPU
{41C74675-6234-41F2-9B8A-4D06159D2A81}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{41C74675-6234-41F2-9B8A-4D06159D2A81}.Debug|Any CPU.Build.0 = Debug|Any CPU
{41C74675-6234-41F2-9B8A-4D06159D2A81}.Release|Any CPU.ActiveCfg = Release|Any CPU
{41C74675-6234-41F2-9B8A-4D06159D2A81}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2A1729E7-0ED9-48D5-84EB-897B28B15D78}
EndGlobalSection
EndGlobal

总结:

  根据项目类型,保留对应项目引用。

四、开发测试

4.1、打包项目文件

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageType>Template</PackageType>
<PackageVersion>1.0.0.1</PackageVersion>
<PackageId>sample.template</PackageId>
<Title>项目模板案例</Title>
<Authors>flightengine</Authors>
<Description>项目模板案例</Description>
<PackageTags>dotnet-new;templates</PackageTags>
<TargetFramework>net6.0</TargetFramework> <IncludeContentInPack>true</IncludeContentInPack>
<IncludeBuildOutput>false</IncludeBuildOutput>
<ContentTargetFolders>content</ContentTargetFolders>
</PropertyGroup> <ItemGroup>
<!--PackagePath="content" 保持文件夹\文件的层级结构,否则所有文件都在根目录-->
<Content Include="..\net6.0\**\*" PackagePath="content" Exclude="..\net6.0\**\bin\**;..\net6.0\**\obj\**;..\net6.0\**\.vs\**" />
<Compile Remove="..\net6.0\**\*" />
</ItemGroup>
</Project>

总结:

  PackagePath定义很重要

4.2、编译打包

net6.0pack文件夹下执行:

dotnet pack 

4.3、安装包

dotnet new --install sample.template.1.0.0.1.nupkg

生成到 net6.0pack\bin\Debug 文件夹

4.4、卸载包

dotnet new --uninstall sample.template

开发中修改后,先执行卸载再安装模板,后vs或者cli测试。

4.5、安装

visual studio:

勾选避免生成的代码层次与模板项目定义不一致。

4.6、上传

执行批处理文件

@echo off
:: 解决中文乱码
chcp 65001
set PackageVersion="1.0.0.1"
del .\PublishNuget\*.nupkg dotnet clean .\net6.0pack.csproj
dotnet pack .\net6.0pack.csproj -p:PackageVersion=%PackageVersion% -c Release -o .\PublishNuget :: dotnet nuget push 上传包源服务器 pause

生成到 net6.0pack\PublishNuget 文件夹,可以再结合上传包源服务器命令。

五、案例源码

https://github.com/yinyunpan/template

六、参考

6.1、官方或者第三方包参考

https://dotnetnew.azurewebsites.net/

搜索包,然后到 https://www.nuget.org/ 下载,分析别人是如何实现的。

6.2、文档

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

官网文档各个参数含义,有些特殊参数注释\案例写不是很明白。

https://github.com/sayedihashimi/template-sample

实际开发中遇到各种问题场景的分析及其解决办法,总结的很不错。

asp.net core web 解决方案多项目模板制作打包总结的更多相关文章

  1. ASP.NET Core Web多语言项目

    公司效益好了,准备和国外做生意,这个时候就需要多语言了. > 1. 这是一个ASP.NET Core Web多语言项目,主要展示项目的不同: > 2. 第一种:www.xxx.com/en ...

  2. 在ASP.NET Core Web API中为RESTful服务增加对HAL的支持

    HAL(Hypertext Application Language,超文本应用语言)是一种RESTful API的数据格式风格,为RESTful API的设计提供了接口规范,同时也降低了客户端与服务 ...

  3. [03-2]VS2017 创建 ASP.NET Core Web 程序

    VS2017 创建 ASP.NET Core Web 程序 本文作者:梁桐铭- 微软最有价值专家(Microsoft MVP) 文章会随着版本进行更新,关注我获取最新版本 本文出自<从零开始学 ...

  4. Asp.Net Core Web Api 使用 Swagger 生成 api 说明文档

    最近使用 Asp.Net Core Web Api 开发项目服务端.Swagger 是最受欢迎的 REST APIs 文档生成工具之一,进入我的视野.以下为学习应用情况的整理. 一.Swagger 介 ...

  5. ASP.NET Core Web 支付功能接入 支付宝-电脑网页支付篇

    这篇文章将介绍ASP.NET Core中使用 开源项目 Payment,实现接入支付宝-电脑网页支付接口及同步跳转及异步通知功能. 开发环境:Win 10 x64.VS2017 15.6.4..NET ...

  6. ASP.NET Core Web 支付功能接入 微信-扫码支付篇

    这篇文章将介绍ASP.NET Core中使用 开源项目 Payment,实现接入微信-扫码支付及异步通知功能. 开发环境:Win 10 x64.VS2017 15.6.4..NET Core SDK ...

  7. Asp.Net Core Web应用程序—探索

    前言 作为一个Windows系统下的开发者,我对于Core的使用机会几乎为0,但是考虑到微软的战略规划,我觉得,Core还是有先了解起来的必要. 因为,目前微软已经搞出了两个框架了,一个是Net标准( ...

  8. 【转载】ASP.NET Core Web 支付功能接入 微信-扫码支付篇

    转自:http://www.cnblogs.com/essenroc/p/8630730.html 这篇文章将介绍ASP.NET Core中使用 开源项目 Payment,实现接入微信-扫码支付及异步 ...

  9. 【转载】ASP.NET Core Web 支付功能接入 支付宝-电脑网页支付篇

    转自:http://www.cnblogs.com/essenroc/p/8627775.html 这篇文章将介绍ASP.NET Core中使用 开源项目 Payment,实现接入支付宝-电脑网页支付 ...

随机推荐

  1. Java核心知识体系3:异常机制详解

    1 什么是异常 异常是指程序在运行过程中发生的,由于外部问题导致的运行异常事件,如:文件找不到.网络连接失败.空指针.非法参数等. 异常是一个事件,它发生在程序运行期间,且中断程序的运行. Java ...

  2. Min GW 安装教程(转载)

    下载方式一:1.百度搜索关键词"mingw",点击第一个:2.进入官网后,点击右上角的"Downloads":3.进入第三个页面后,点击"mingw- ...

  3. 羽夏看Linux内核——引导启动(下)

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.如有好的建议,欢迎反馈.码字不易,如果本篇文章有帮助你的,如有闲钱,可以打赏支持我的创作.如想转载,请把我的转载信息附在文章后面,并 ...

  4. Spring源码 20 手写模拟源码

    参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...

  5. 一个非常简单用.NET操作RabbitMQ的方法

    RabbitMQ作为一款主流的消息队列工具早已广受欢迎.相比于其它的MQ工具,RabbitMQ支持的语言更多.功能更完善. 本文提供一种市面上最/极简单的使用RabbitMQ的方式(支持.NET/.N ...

  6. 275. H 指数 II--Leetcode_二分

    来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/h-index-ii 著作权归领扣网络所有.商业转载请联系官方授权,非商业转载请注明出处. 题目的大意是 ...

  7. docker启动失败问题

    内核3.10,systemctl start docker 被阻塞,没有返回,查看状态为启动中. 某兄弟机器安装docker之后,发现systemctl start docker的时候阻塞,由于排查走 ...

  8. idea主类main左侧栏启动按钮消失原因

    今天在开发完一个小项目后,打开idea发现我的springboot项目的启动类左侧栏的按钮消失了,然后我又去看了看mapp等文件的调转也全部消失了,我就很纳闷是不是idea配置坏了,赶忙点击导航栏的按 ...

  9. C#基础_析构函数

    C#析构函数 1. 析构函数的定义与注意的问题 析构函数用于释放被占用的系统资源. 析构函数的名字由符号"-"加类名组成. 使用析构函数时,应该注意下面的问题: ?只能在类中使用析 ...

  10. ubuntu 安装及配置Apache

    一.下载.启动apache2 sudo apt-get install apache2 sudo /etc/init.d/apache2 restart 二.修改配置文件 1.更改网站根目录 sudo ...