28

我正在开发一个构建ORM 层的自定义 MSBuild 任务,并在项目中使用它。我受到 Visual Studio 坚持 MSBuild 任务 DLL 而不放手的行为的阻碍。

我想像这样组织我的解决方案;

My Solution
 |
 +- (1) ORM Layer Custom Task Project
 |  |
 |  +- BuildOrmLayerTask.cs     // here's my task
 |  
 +- (2) Business Logic Project  // and here's the project that uses it.
    |
    +- <UsingTask TaskName="BuildOrmLayerTask" AssemblyFile="$(TaskAssembly)" />

但是,当项目 (2) 构建时,它会锁定项目 (1) 的程序集。所以现在我不能在不关闭解决方案并重新打开它的情况下再次构建项目 (1)。

有什么方法可以组织事情,以便自定义构建任务不会被 Visual Studio 锁定?

4

3 回答 3

26

编辑: 赛义德·易卜拉欣·哈希米(Sayed Ibrahim Hashimi),他在 msbuild 上写过这本书,建议使用AppDomainIsolatedTask类以获得更好的方法)

我自己设法解决了这个问题......

找到来自 Microsoft 的 MSBuild 开发人员之一Dan Moseley 的这个论坛帖子:

你好呀,

不幸的是,这是因为 MSBuild 在主应用程序域中加载任务程序集。CLR 不允许从应用程序域卸载程序集,因为这允许对它们进行重要的优化。

我建议的唯一解决方法是调用 tomsbuild.exe 来构建使用该任务的项目。为此,请在 VS 中创建 MSBuild.exe <> 作为外部工具。

msbuild 上的Dan
开发人员
DanMoseley - MSFT

因此,似乎要停止锁定,您必须生成一个新的 MSBuild.exe 进程。它不可能是在 Visual Studio 中运行的那个,因为当 MSBuild 运行时,它会将任务加载到 Visual Studio 的主应用程序域中,并且永远无法卸载。

  • 创建一个新的 MSBuild 项目(一个 .csproj 或类似的),它会覆盖“构建”目标并执行您的自定义操作,例如;

    <!-- fragment of Prebuild.csproj -->   
    <Target Name="Build">   
         <BuildOrmLayerTask Repository="$(Repository)" />   
    </Target>
    
  • 如果需要,可以将其添加到 Visual Studio,但使用配置管理器确保它在任何配置中构建。让 VS 处理源代码控制等,而不是构建。

  • 编辑依赖的项目的 .csproj 文件Prebuild.csproj。添加一个BeforeBuild使用该Exec任务调用 MSBuild 的目标。这将启动一个新进程,当该进程结束时,文件锁将被释放。例子;

    <PropertyGroup>   
         <PrebuildProject>$(SolutionDir)Prebuild\Prebuild.csproj</PrebuildProject>   
    </PropertyGroup>   
    <Target Name="BeforeBuild">   
         <Exec Command="msbuild.exe &quot;$(PrebuildProject)&quot;" />   
    </Target>
    

现在,当您构建依赖项目时,它会在运行编译之前在新进程中执行 MSBuild。

于 2010-08-04T13:25:31.987 回答
4

您可以编辑项目文件并包含以下属性声明吗

<PropertyGroup>
    <GenerateResourceNeverLockTypeAssemblies>true</GenerateResourceNeverLockTypeAssemblies>
</PropertyGroup>

让我知道这是否适合你。

于 2010-08-04T06:53:20.437 回答
3

正如我在针对@Al-Muhandis 的评论中提到的那样,似乎可以围绕自定义任务创建一个包装器,以便包装器被锁定,而不是自定义任务 DLL。我已经对孤立任务项目进行了初步尝试。它可能有问题,目前仅适用于 VS2008。欢迎拉取请求。

该项目的想法是基于以下观察:源自MarshalByRefObject(可能使用AppDomainIsolatedTask)的任务似乎被加载到主应用程序域中以进行反射,但创建了一个新的应用程序域来执行任务。由于加载到主应用程序域似乎仍然会锁定 DLL,因此创建一个 DLL 并使用派生自AppDomainIsolatedTask加载自定义任务 DLL 的任务是很有用的。这样,包装器 DLL 会被锁定,但因为它在自己的应用程序域中执行,所以在卸载包装器任务的执行域时会卸载自定义任务 DLL。此过程可避免在构建完成后锁定自定义任务 DLL。

于 2014-07-10T19:10:24.340 回答