我在尝试识别为什么MSBuild正在阻止访问我刚创建的一个新T4模板中使用的dll时遇到了很多麻烦。
问题有点难以解释(正如标题所示)。
我创建了一个T4模板,用于生成一个包装我们拥有的N个其他类的c#类。这是我想出来的解决方案,以在同一端点上公开多个WCF服务。
模板代码本身使用了一个包含各种扩展方法的程序集(Mobiltec.Framework.dll),以简化模板代码。起初,我只是将.tt文件添加到项目中并继续使用:每当.tt更改时,它都会更新生成的文件,就像预期的那样。
由于此模板读取其他程序集并基于它们生成类,因此我希望确保它在每次构建时转换输出,以防止开发人员忘记更新输出等事情。
经过几天的搜索,我终于找到了一个相当不错的解决方案,模板在每次构建时都被转换得“几乎”完美。问题是,每当我构建项目并转换模板时,它就会锁定对前面提到的dll的访问,从而防止我在之后删除或更新文件。我必须关闭Visual Studio才能释放该文件。
现在,在本地开发人员机器上,这不是一个很大的问题,但它会使我们的构建失败,因为输出都在同一个文件夹中:
- 构建过程开始编译我们的主解决方案
- 包含T4模板的项目被编译,并生成了类
- 另一个项目被编译,并尝试更改输出文件夹中的dll,经过10次尝试后构建失败
这是文本模板系统中的错误还是我可能犯了一些错误导致文件被锁定?
更新
我将尝试更好地解释这里的所有设置,以便您们可以更好地理解问题。
有一个.tt模板文件,总共有四个Web应用程序(其中有4个)。此模板负责自动生成所有WCF服务契约的包装器类。合同本身分为另一个程序集(也是每个组件的一个)中,以便客户端可以共享而不携带所有其他依赖项。
我不得不实现一堆方法,使用反射来打印来自每个程序集的签名、成员和类型,以生成可以编译为有效类的文本。我在一个公共程序集上实现了这些方法。
然后,每个tt文件都引用此公共程序集,以及服务合同程序集,以生成此包装器类。例如,模板有一堆像这样的行:
<#@ assembly name="Mobiltec.M3.EG.Services.dll" #>
<#@ assembly name="Mobiltec.M3.Common.dll" #>
由于我们需要在每次构建时转换这些模板,我已更改了项目文件以实现这一点,并安装了Visual Studio SDK和Visualization and Modeling SDK,按照此建议进行操作。
现在,每当我对任何程序集或其依赖项中的代码进行更改时,都会收到以下消息:
Error 1516 Compiling transformation: Metadata file 'Mobiltec.M3.EG.Services.dll' could not be found. Line=0, Column=0 Mobiltec.M3.EG
Error 1517 Compiling transformation: Metadata file 'Mobiltec.M3.Common.dll' could not be found. Line=0, Column=0 Mobiltec.M3.EG
或者:
Error 395 Could not copy "D:\TFS05\M3\Desenvolvimento\Feature-ODataM3S\ProjetosManutencao\Mobiltec.M3.Common\Mobiltec.M3.Common.Desktop\bin\Mobiltec.M3.Common.dll" to "bin\Mobiltec.M3.Common.dll". Exceeded retry count of 10. Failed. Mobiltec.M3.EG
Error 396 Unable to copy file "D:\TFS05\M3\Desenvolvimento\Feature-ODataM3S\ProjetosManutencao\Mobiltec.M3.Common\Mobiltec.M3.Common.Desktop\bin\Mobiltec.M3.Common.dll" to "bin\Mobiltec.M3.Common.dll". The process cannot access the file 'bin\Mobiltec.M3.Common.dll' because it is being used by another process. Mobiltec.M3.EG
Error 407 Could not copy "D:\TFS05\M3\Desenvolvimento\Feature-ODataM3S\ProjetosManutencao\Mobiltec.M3.EG\Mobiltec.M3.EG.Services\bin\Debug\Mobiltec.M3.EG.Services.dll" to "bin\Mobiltec.M3.EG.Services.dll". Exceeded retry count of 10. Failed. Mobiltec.M3.EG
Error 408 Unable to copy file "D:\TFS05\M3\Desenvolvimento\Feature-ODataM3S\ProjetosManutencao\Mobiltec.M3.EG\Mobiltec.M3.EG.Services\bin\Debug\Mobiltec.M3.EG.Services.dll" to "bin\Mobiltec.M3.EG.Services.dll". The process cannot access the file 'bin\Mobiltec.M3.EG.Services.dll' because it is being used by another process. Mobiltec.M3.EG
此外,当我尝试通过Visual Studio删除bin/obj文件夹时,会出现以下错误:
如果我手动尝试在Windows资源管理器中删除bin文件夹中的文件,则会出现以下错误:
基本上,这归结为MSBuild锁定了Web应用程序项目的bin文件夹中所有明确引用的文件(.tt中的所有文件)。每当项目重建时,引用的dll被重新复制到项目自己的输出文件夹中,由于Windows无法覆盖“正在使用”的文件,因此此过程失败。
唯一能释放锁定的方法就是完全关闭Visual Studio并重新打开它。我尝试手动终止机器上的所有MSBuild进程或关闭并重新打开解决方案,但都不起作用。即使像Unlocker这样的工具也无法删除文件上的锁定(甚至无法检测到它)。
构建服务器上的最初问题也是由相同的问题引起的,但现在已经“解决”,因为我重命名了一个dll。两个不同的项目(Mobiltec.Framework.Desktop
和Mobiltec.Framework.WindowsMobile
)具有相同的输出dll名称(Mobiltec.Framework.dll
),在.tt文件进行转换后,第二个项目尝试覆盖构建全局输出文件夹中的第一个项目(锁定原始的dll),导致整个过程失败。