最近对NuGet很感兴趣,研究了一下,发现NuGet不仅能将package安装到project中,还可以向Visual Studio 的Project Template中添加NuGet package,这样做的好处就是对于频繁用到的package,比如Json.NET, 将其添加到VS 的Project Template中后,每次通过这个Template新建的项目都会自动安装Json.NET这个包,省去了每次新建一个项目都要手动安装一遍的麻烦。
其实过程并不复杂,下面我们以Visual Studio 2013 的Web Project为例,分三个步骤来说明如何向Template中添加NuGet包。
一. 定位Template文件
VS的项目模板文件的后缀是.vstemplate,通常在:C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\ProjectTemplates里面。在这个文件夹下项目模板大致是以编程语言分类的,比如我们选择C#语言,在Web->Visual Studio 2012节点下,右侧这些Web Application
对应的模板就在C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\ProjectTemplates\CSharp\Web\Version2012\1033 下面。
而Common7\IDE\ProjectTemplates\Web这个文件夹里是则是新建WebSite的模板。
例外的是如果选中Templates->Visual C#->Web,双击右侧"ASP.NET Web Application"
弹出的对话框里显示的这些Project Template:
它们并不是在Common7\IDE\ProjectTemplates里,而是在Common7\IDE\WebTemplates这个文件夹里面。
二. 修改vstemplate 文件
我们以Visual C#->Web->ASP.NET Web Application->MVC为例,找到对应的vstemplate 文件:"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\WebTemplates\MVC\CSharp\1033\MvcBasicApplicationv5.0\MvcBasicApplication.cshtml.vstemplate"打开会发现这其实是一个XML格式的文件。定位到<WizardExtension>
1 <WizardExtension> 2 3 <Assembly>NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</Assembly> 4 5 <FullClassName>NuGet.VisualStudio.TemplateWizard</FullClassName> 6 7 </WizardExtension> 8 9 <WizardData> 10 11 <packages repository="registry" keyName="AspNetWebFrameworksAndTools5" isPreunzipped="true"> 12 13 <package id="bootstrap" version="3.0.0" skipAssemblyReferences="true" /> 14 15 <package id="jQuery" version="1.10.2" skipAssemblyReferences="true" /> 16 17 <package id="Microsoft.AspNet.Razor" version="3.2.2" skipAssemblyReferences="true" /> 18 19 <package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" skipAssemblyReferences="true" /> 20 21 <package id="Microsoft.AspNet.WebPages" version="3.2.2" skipAssemblyReferences="true" /> 22 23 <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" skipAssemblyReferences="true" /> 24 25 <package id="Microsoft.AspNet.Mvc" version="5.2.2" skipAssemblyReferences="true" /> 26 27 <package id="Modernizr" version="2.6.2" skipAssemblyReferences="true" /> 28 29 <package id="Antlr" version="3.4.1.9004" skipAssemblyReferences="true" /> 30 31 <package id="WebGrease" version="1.5.2" skipAssemblyReferences="true" /> 32 33 <package id="Respond" version="1.2.0" skipAssemblyReferences="true" /> 34 35 <package id="jQuery.Validation" version="1.11.1" skipAssemblyReferences="true"/> 36 37 <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.2" skipAssemblyReferences="true"/> 38 39 40 41 </packages> 42 43 </WizardData>
WizardExtension中的NuGet.VisualStudio.Interop程序集是向模板添加包的关键,如果你浏览过NuGet的源代码,你会发现NuGet.VisualStudio.Interop.dll只包含一个TemplateWizard类,这个类只是一个简单的封装,它调用了NuGet.VisualStudio.dll里面的真正实现,此外这个dll的版本从不改变,永远是1.0.0.0, 所以你不用担心NuGet版本升级导致你的Template不能用了。
接下来WizardData下面是模板中添加的所有包的一个列表,
<packages repository="registry" keyName="AspNetWebFrameworksAndTools5" isPreunzipped="true">
repository="registry" keyName="AspNetWebFrameworksAndTools5" 表示Nuget 要从注册表中读取名为"AspNetWebFrameworksAndTools5"键的值,来获取本地NuGet仓库的位置,是的,本地而不是网络,也就是说当你创建Project时,VS是从本地读取需要用到的包,然后安装到你的项目中的,我猜这样是为了让用户在离线状态下也能正常创建新项目。
打开注册表编辑器在HKEY_LOCAL_MACHINE\SOFTWARE[\Wow6432Node]\NuGet\Repository下,你可以看到所有这些本地的NuGet仓库的位置。
打开其中一个仓库的目录,我们发现目录下面包含很多包,每个包不仅有.nupkg文件,还有.nupkg解压过的文件夹(*.nupkg 实际上是zip格式的压缩包,微软总喜欢起不同的扩展名),这实际上是一种优化措施,也就是如果isPreunzipped="true",安装包时就直接从解压过的文件夹里读取数据,省去了解压.nupkg的步骤,创建新项目的过程自然就会快一些了。
最后,我们在<packages>节点下面加入想要添加的包:
<package id="Newtonsoft.Json" version="6.0.8" />
保存vstemplate文件。
三. 复制需要添加的包到相应文件夹
正如第二步所说的那样,VS需要从本地读取包,如果改完Template后你直接就用这个Template创建新的Project, VS会弹出错误对话框,提示你无法在本地对应的NuGet仓库下发现指定的包。你要做的就是找到你修改的vstemplate文件中keyName对应的本地NuGet仓库的位置,解压你需要添加的NuGet包,copy解压得到的文件夹到这个位置。
大功告成,现在当你用这个修改后模板创建新项目后,就会发现Json.NET已经自动地安装到了新项目中。