自定义MSBuild任务锁定程序集

时间:2010-12-16 12:25:07

标签: msbuild msbuild-task

乍一看,我的问题似乎很常见:我的一些项目中有一个自定义的MS Build任务。编译项目后,我无法再编译构建任务 - 构建任务程序集被Visual Studio锁定。

我在这里发现很多帖子说“只是从AppDomainIsolatedTask继承”。

我的任务已经完成。该程序集除此任务外不包含其他内容。似乎卸载了AppDomain,至少触发了DomainUnload事件。并且,依赖程序集正确卸载。

但是,包含构建任务本身的程序集已被devenv.exe锁定(我已经过ProcessExplorer对其进行了双重检查)。

我发现另一篇文章说'将GenerateResourceNeverLockTypeAssemblies属性设置为true',听起来很有希望,但也没有帮助。

所以,我想知道还有什么可能出错。无论我使用VS2008还是2010,行为都是一样的。

2 个答案:

答案 0 :(得分:0)

这样的事情可能非常棘手。有很多要考虑LoaderOptimization,ShadowCopy等。

AppDomainIsolatedTask并不意味着"不污染构建域"。 这意味着"在另一个域中运行我的代码" - 任务类型本身仍然加载到构建引擎域中。这是不幸的,因为我觉得大多数人都把它解释为前者。要使此专用任务类型起作用,您还必须使用[LoadInSeparateAppDomain]对任务进行装饰。这仍然无法解决您的问题。

ProcessExplorer具有这个方便的.NET程序集视图,您可以使用它来识别哪个域具有程序集句柄。正如您所知,devenv.exe已将其锁定。

Useful feature

由于您将具有任务的DLL加载到VS用于构建内容的域中,因此您将遇到此问题。

您需要做的是引入另一层间接。

选项

  1. 您可以将任务转换为inline code task
  2. 您可以使用内联代码任务加载静态任务并委托给它。
  3. 我提供了方法#2的示例 此屏幕截图验证了我的自定义库在MSBuild应用程序域中不存在的结果。

    定义内联任务,如此

       
    <Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">  
      <UsingTask  
        TaskName="RunOtherTask"  
        TaskFactory="CodeTaskFactory"  AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >  
        <ParameterGroup />  
        <Task>
          <Using Namespace="MyTasks" />  
          <Code Type="Class" Language="cs">  
    <![CDATA[ 
    using System;  
    using System.Reflection;
    using Microsoft.Build.Framework;  
    using Microsoft.Build.Utilities;  
    
    namespace MyTasks {      
        public class RunOtherTask : Task {  
            public override bool Execute() { 
               var remoteTask = CreateInstanceInSeparateDomain();      
               remoteTask.BuildEngine = this.BuildEngine;
               remoteTask.Execute();
    
               return true;  
            }
    
            private ITask CreateInstanceInSeparateDomain() {
                var thisAssembly = Assembly.GetExecutingAssembly();
    
                var setup = new AppDomainSetup {
                    ShadowCopyFiles = true.ToString(),              
                    LoaderOptimization = LoaderOptimization.MultiDomainHost                 
                };
    
                var domain = AppDomain.CreateDomain("MyDomain", null, setup);
                var handle = domain.CreateInstanceFrom(@"C:\ClassLibrary1.dll", "ClassLibrary1.SimpleTask");
    
                return (ITask)handle.Unwrap();
            }
        }
    } 
     ]]>
          </Code>  
        </Task>  
      </UsingTask>  
    
      <Target Name="RunTask">  
        <RunOtherTask /> 
      </Target>
    
    </Project>  
    

    只要您的任务实现ITask(它必须),它就会起作用。 您需要在新实例化的任务上设置引擎属性,以使一切正常工作。

    Class Library1 is not loaded

答案 1 :(得分:-3)

可以通过更改文件系统权限安全性来解决。将您当前的用户设置为锁定文件的共同所有者。