2012-02-02 68 views
2

我已经经历了与此相关的SO问题,并且无法找到任何问题,因此我在问这个问题。msbuild中的反射问题,devenv很好

我有一个buildtask(添加作为AfterBuild目标),以验证类型的名称。这些类型名称是正在构建的silverlight项目的完全限定类型名称。

要解决这些类型名称,我使用Type.ReflectionOnlyGetType()。要加载相关程序集,我使用Assembly.ReflectionOnlyLoadFrom(filepath)处理AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve事件以从项目输出路径和silverlight安装路径中加载项目特定程序集。

这工作完全正常,当我建的项目是在VS2010,但当我的MSBuild建立C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "C:\Root\branches\x.x.x\clients.sln" /t:rebuild /p:Configuration=Debug "/p:Platform=Any CPU" /v:quiet /maxcpucount:1

虽然与MSBuild的基础上,ReflectionOnlyAssemblyResolve事件被触发为"System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e",这是加载失败从silverlight安装路径。但是,探测正在尝试"C:/WINDOWS/Microsoft.NET/Framework/v4.0.30319/System.DLL"这个系统组件,由于主要版本不匹配而失败。

以下是我的代码剥离版本,具体到这个问题:

public class ValidateTypeTask : Task 
    { 
     public override bool Execute() 
     { 
      Initialize(); 

      List<string> typeNames = GetTypes(); 
      foreach (var typeName in typeNames) 
      { 
       var isResolved = IsResolvable(typeName); 
       if (!isResolved) 
       { 
        return false; 
       } 
      } 

      CleanUp(); 

      return true; 
     } 

     private void Initialize() 
     { 
      AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler(CurrentDomain_ReflectionOnlyAssemblyResolve); 
     } 

     Assembly CurrentDomain_ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args) 
     { 
      Assembly loadedAssembly = null; 
      Exception loadedException = null; 
      try 
      { 
       loadedAssembly = Assembly.ReflectionOnlyLoad(args.Name);//this will fail always 
      } 
      catch (Exception ex) 
      { 
       loadedException = ex; 
      } 

      if (loadedAssembly != null) 
      { 
       return loadedAssembly; 
      } 

      string assemblyPath = string.Empty; 
      var assemblyName = new AssemblyName(args.Name); 
      if (args.Name.StartsWith("System")) 
      { 
       assemblyPath = @"c:\Program Files\Reference Assemblies\Microsoft\Framework\Silverlight\v4.0"; 
      } 
      else 
      { 
       assemblyPath = @"C:\Root\branches\x.x.x\bin\debug"; 
      } 
      assemblyPath = string.Format(@"{0}\{1}.dll", assemblyPath, assemblyName.Name); 
      if (File.Exists(assemblyPath)) 
      { 
       loadedAssembly = Assembly.ReflectionOnlyLoadFrom(assemblyPath); 
      } 

      if (loadedAssembly == null) 
      { 
       throw loadedException; 
      } 

      return loadedAssembly; 
     } 
     private void CleanUp() 
     { 
      AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve -= new ResolveEventHandler(CurrentDomain_ReflectionOnlyAssemblyResolve); 
     } 
     private List<string> GetTypes() 
     { 
      return new List<string>(); 
     } 
     private bool IsResolvable(string typeName) 
     { 
      Type resolvedType = null; 
      try 
      { 
       resolvedType = Type.ReflectionOnlyGetType(typeName, true, true); 
      } 
      catch (Exception ex) 
      { 
      } 

      if (resolvedType != null) 
      { 
       return true; 
      } 

      return false; 
     } 
    } 

我得到的例外如下:

System.IO.FileLoadException: Could not load file or assembly 'System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040) 
    File name: 'System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' 
    at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, Boolean loadTypeFromPartialName, ObjectHandleOnStack type) 
    at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, Boolean loadTypeFromPartialName) 
    at System.RuntimeType.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark) 
    at System.Type.ReflectionOnlyGetType(String typeName, Boolean throwIfNotFound, Boolean ignoreCase) 
    at in c:\root\x.xx.x\BuildTasks\ValidateTypesTask.cs line xxx 

    Assembly manager loaded from: C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\clr.dll 
    Running under executable C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild.exe 
    --- A detailed error log follows. 

    === Pre-bind state information === 
    LOG: User = domain\username 
    LOG: DisplayName = System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e 
    (Fully-specified) 
    LOG: Appbase = file:///C:/WINDOWS/Microsoft.NET/Framework/v4.0.30319/ 
    LOG: Initial PrivatePath = NULL 
    Calling assembly : (Unknown). 
    === 
    LOG: This is an inspection only bind. 
    LOG: Using application configuration file: C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\msbuild.exe.Config 
    LOG: Using host configuration file: 
    LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\config\machine.config. 
    LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v4.0.30319/System.DLL. 
    WRN: Comparing the assembly name resulted in the mismatch: Major Version 
    ERR: Failed to complete setup of assembly (hr = 0x80131040). Probing terminated. 

我也曾尝试包括Silverlight的程序集路径进入AssemblySearchPaths项目属性让它成为探测网址的一部分,并且仍然相同。

+0

尝试更新项目引用或通过ToolsVersion = 2.0 – KMoraz 2012-02-03 08:58:59

+0

@KMoraz我尝试删除并添加系统组件引用,只是为了更新项目引用,并没有帮助。我无法将ToolsVersion设置为2,因为目标是Silverlight 4.0。另外,我不想设置ToolsVersion,因为在VS2010中一切都很好,很好。 – AnbeSivam 2012-02-06 05:25:49

回答

1

我相信这不是我在上面发布的问题的答案。但是,这是我解决它的方式。

我已经通过论坛和文档,发现了DEVENV和MSBUILD之间的基本区别。当用MSBuild程序集解析进行构建时,发生的方式比Devenv严格。

另外,我已通过Assembly.LoadFromAssembly.ReflectionOnlyLoadFrom之间的差别消失了。 Assembly.RefelectionOnlyLoadFrom只考虑文件名,不检查版本等。这是MSBuild从.Net 4.0堆栈加载System.dll的地方,因为它必须从silverlight安装路径加载System.dll。

考虑到所有这些,我尝试使用Assembly.LoadFrom加载程序集并使用Type.GetType来解析类型。这一次,我碰到StackOverflowException,因为重复触发了所有加载的程序集的AssemblyResolve事件。

这是在我以为装载组件到一个单独的应用程序域,这样我也可以卸载装载组件。我发现this文章非常有用,并遵循类似的模式来解决问题。

虽然我手边已经解决了问题,但我不想为此答案获得积分。我仍然觉得我没有提供MSBuild的问题的答案。

希望这可能会对其他人有所帮助。

0

考虑使用AppDomainIsolatedTask作为基类,然后重试。这使得处理程序集变得更容易,因为程序集不会被加载到msbuild AppDomain中。

这也会将您的事件调用隔离到您自己的AppDomain。所以MsBuild也不能打扰你。