msbuild 中的反射问题,devenv 很好

发布于 2025-01-02 06:37:21 字数 6094 浏览 0 评论 0原文

我已经解决了与此相关的问题,但找不到任何与此问题相关的问题,因此,我问这个问题。

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

为了解析这些类型名称,我使用 Type.ReflectionOnlyGetType()。为了加载依赖程序集,我处理 AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve 事件,以使用 Assembly.ReflectionOnlyLoadFrom(filepath)< 从项目输出路径加载项目特定程序集,并从 silverlight 安装路径加载 silverlight 基础程序集/代码>。

当我在 VS2010 中构建项目时,这工作得很好,但是当我使用 MSBuild 构建时失败C:\WINDOWS\Microsoft.NET\Framework\v4 .0.30319\msbuild.exe "C:\Root\branches\xxx\clients.sln" /t:rebuild /p:Configuration=Debug "/p:Platform=Any CPU" /v:quiet /maxcpucount:1

使用 MSBuild 进行构建时,"System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" 会触发 ReflectionOnlyAssemblyResolve 事件 这是从 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 项目属性中,以使其成为探测 url 的一部分,并且仍然相同。

I have gone through SO questions related to this and could not find any for this issue and hence, I am asking this question.

I have a buildtask (added as AfterBuild target), to validate types names. These type names are fully qualified type names from the silverlight projects that are being build.

To resolve these type names, I use Type.ReflectionOnlyGetType(). To load the dependent assemblies I handle AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve event to load project specific assemblies from the project output path and silverlight base assemblies from the silverlight installation path using Assembly.ReflectionOnlyLoadFrom(filepath).

This works perfectly fine, when I build the projects in VS2010, but fails when I build with MSBuild i.e. 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

While building with MSBuild, the ReflectionOnlyAssemblyResolve event is fired for "System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" and this was loaded from the silverlight installation path. But, the probing is trying for this system assembly in "C:/WINDOWS/Microsoft.NET/Framework/v4.0.30319/System.DLL", which fail as the major version wont match.

Following is the stripped version of my code, specific to this problem:

  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;
        }
    }

The exception I get is as follows:

  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.

I have also tried including the silverlight assemblies path into AssemblySearchPaths project property to let this be part of the probing urls and still the same.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

莫言歌 2025-01-09 06:37:21

我确信这不是我上面发布的问题的答案。但是,我就是这样解决的。

我浏览了论坛和文档,发现了 DEVENV 和 MSBUILD 之间的基本区别。使用 MSBuild 进行构建时,程序集解析的方式比 Devenv 中的严格。

另外,我还了解了 Assembly.LoadFromAssembly.ReflectionOnlyLoadFrom 之间的区别。 Assembly.RefelectionOnlyLoadFrom 仅考虑文件名,不检查版本等,这是 MSBuild 从 .Net 4.0 堆栈加载 System.dll 的位置,因为它必须从以下位置加载 System.dll silverlight安装路径。

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

这时我想到将程序集加载到单独的应用程序域中,以便我也可以卸载已加载的程序集。我发现这篇文章非常有用,并遵循类似的模式来解决该问题。

尽管我手头已经解决了问题,但我不想因为这个答案而得分。我仍然觉得我没有提供 MSBuild 问题的答案。

希望这对其他人有帮助。

I am sure that this is not the answer for the problem I posted above. But, this is how I resolved it.

I had gone through forums and documentation and found the basic difference between DEVENV and MSBUILD. When building with MSBuild assembly resolution happens in a strict manner than in Devenv.

Also, I had gone through the difference between Assembly.LoadFrom and Assembly.ReflectionOnlyLoadFrom. Assembly.RefelectionOnlyLoadFrom considers just the file name and does not check on version, etc., This is where MSBuild was loading System.dll from the .Net 4.0 stack where as it has to load System.dll from the silverlight installation path.

With all these in mind, I tried to load the assemblies using Assembly.LoadFrom and used Type.GetType to resolve the types. This time, I ran into StackOverflowException as the AssemblyResolve event was triggered for all the loaded assemblies repeatedly.

This is when I thought of loading the assemblies into a separate appdomain so that I can also unload the loaded assemblies. I found this article very useful and followed a similar pattern to solve the issue.

Though I have the solved issue on hand, I do not want to gain points for this answer. I still feel I have not provided the answer for the issue with MSBuild.

Hope this might be helpful for others.

挽梦忆笙歌 2025-01-09 06:37:21

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

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

Consider using AppDomainIsolatedTask as base class and try again. This makes handling assemblies a lot easier becasuse the assemblies do not get loaded into the msbuild AppDomain.

This also isolates your event calls to your own AppDomain. So MsBuild also can not disturb you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文