多项目模板(projectgroup)能统一参数替换、自动建立项目引用并规避命名空间不一致等问题,而单项目模板仅为静态快照,无法跨项目联动;必须通过vsix打包分发,且需在主/子vstemplate中双向声明参数、用guid绑定引用关系。

直接用多项目模板(ProjectGroup)搭框架,比手动新建+复制粘贴快 5 倍以上,且能规避 80% 的引用错位、命名空间不一致、NuGet 版本冲突问题。
为什么不能用“导出单个项目”做企业框架
导出单个项目生成的是 .zip 模板,它本质是静态快照:所有路径、命名空间、项目 GUID 都被固化,无法跨项目联动替换。比如你导出一个 MyApp.Domain 项目,再导出一个 MyApp.WebAPI,两者之间没有逻辑绑定——新建时用户输的 $safeprojectname$ 不会自动同步到两个项目的命名空间里,MyApp.WebAPI 引用 MyApp.Domain 的关系也不会自动生成。
常见错误现象:
- 新建后出现
The type or namespace name 'Domain' does not exist -
ProjectReference显示为灰色,提示“未加载” - 多个项目中
AssemblyInfo.cs里的Company字段仍是“DefaultCompany”
根本原因:单项目模板不支持 <templateparameters></templateparameters> 跨项目广播,也不支持 <projectcollection></projectcollection> 拓扑定义。
多项目模板必须用 VSIX 打包才能可靠分发
VSIX 是 Visual Studio 唯一支持“安装即生效”的模板分发机制。把模板文件夹直接丢进 %USERPROFILE%\Documents\Visual Studio 2022\Templates\ProjectTemplates 会失效,因为:
- VS 2022 默认禁用本地未签名模板(尤其启用了“仅允许已验证扩展”策略的团队环境)
- 子项目中的
.csproj文件若含PackageReference,需通过 VSIX 的extension.vsixmanifest显式声明依赖项,否则 NuGet restore 失败 - 自定义参数如
$ext_companyname$必须在 VSIX 的source.extension.vsixmanifest中注册为Asset类型Microsoft.VisualStudio.ProjectTemplate,否则不识别
实操建议:
Visual Studio 18.8.1 官方固定版本安装引导程序,当前条目使用微软发布历史中的 Professional Web Installer,适合旧项目兼容、环境回退、复现特定构建链和排查版本差异等场景。
- 新建项目时选 “VSIX Project”,不是 “Project Template”(后者是旧版,不支持
Type="ProjectGroup") - 在 VSIX 项目中添加 “Multi-Project Template” 项,它会自动生成带
<projecttemplatelink></projecttemplatelink>的.vstemplate - 每个子项目模板必须放在独立文件夹内,并在主
.vstemplate中用<projecttemplatelink projectname="$safeprojectname$.Domain"></projecttemplatelink>显式指定名称
分层项目间引用必须靠 ProjectTemplateLink + GUID 关联
想让 WebAPI 自动引用 Domain,不能靠手写 <projectreference></projectreference>,而要利用模板引擎的 GUID 绑定机制。关键点:
- 每个子项目模板的
.vstemplate文件顶部必须声明唯一$guid1$~$guid10$,例如Domain用$guid1$,WebAPI用$guid2$ - 在
WebAPI的.csproj中,写死引用:<projectreference include="..\$safeprojectname$.Domain\$safeprojectname$.Domain.csproj" name="$safeprojectname$.Domain" project="$guid1$"></projectreference> - 模板引擎会在新建时把
$guid1$替换为真实 GUID,并确保该 GUID 与Domain项目的实际ProjectGuid一致
漏掉这步的典型表现:
- 新建解决方案后,
WebAPI的引用显示为“未解析”,右键“重新加载项目”才生效 - 编译时报错:
MSB4057: The target "ResolveProjectReferences" does not exist
模板参数要在 .vstemplate 和子项目中双向声明
只在主 .vstemplate 里写 <parameter name="$ext_companyname$" value="Acme"></parameter> 不够——子项目里的 AssemblyInfo.cs 还得主动读取它。否则所有子项目公司名还是默认值。
正确做法:
- 主
.vstemplate中声明:<templateparameters><parameter name="$ext_companyname$" value="Acme"></parameter></templateparameters> - 每个子项目的
.vstemplate中也加相同声明(否则参数不透传) - 子项目代码文件中用占位符,例如
AssemblyCompany("$ext_companyname$")
容易被忽略的细节:
-
$safeprojectname$是 VS 内置参数,但$ext_*开头的必须显式声明,否则新建时直接报错Invalid template parameter - 如果子项目用了
Directory.Build.props控制版本号,其中的$(Company)变量也得用$ext_companyname$初始化,否则 CI 构建时版本元数据丢失
真正麻烦的从来不是搭结构,而是让所有子项目对同一个输入参数做出一致响应——参数声明漏一处,整套框架就出现“名字对不上”的割裂感。










