"无法加载文件或程序集“System.Core程序,版本= 2.0.5.0,..."异常时,加载可移植类库dynamicaly加载、程序、类库、异常

2023-09-03 04:46:56 作者:自然卷的气质;

首先,我需要强调的是,这是稍有不同的问题比在this螺纹。此外,安装 KB2468871 没有帮助。

我试图简化此问题尽可能。在一般情况下加载桌面应用程序Assembly.LoadFile(...)。

PCL组件

让我们说有一个.NET 4.0的控制台应用程序(称为C)。它引用.NET 4.0组件(称为N4)和PCL组件(称为PCL)。

,其中N4看起来是这样的:

 使用System.Linq的;

命名空间N4
{
    公共类ClassInN4
    {
        公共静态字符串问候()
        {
            返回新的字符串(
                你好,从N4
                .ToCharArray()
                。选择(char.ToUpper)
                .ToArray()
            );
        }
    }
}
 

PCL看起来是这样的:

 使用System.Linq的;

命名空间PCL
{
    公共类ClassInPCL
    {
        公共静态字符串问候()
        {
            返回新的字符串(
                你好,从PCL
                .ToCharArray()
                。选择(char.ToUpper)
                .ToArray()
            );
        }
    }
}
 

和C是这样的:

 使用系统;
使用System.IO;
使用的System.Reflection;
采用N4;
采用PCL;

命名空间Ç
{
    内部类节目
    {
        私有静态无效的主要(字串[] args)
        {
            测试();
            到Console.ReadLine();
        }

        私有静态无效测试()
        {
            测试(N4,ClassInN4.Greet);
            测试(PCL,ClassInPCL.Greet);
        }

        私有静态无效测试(
            串题,
            FUNC<字符串>发电机)
        {
            尝试
            {
                Console.WriteLine(
                    {0}:{1},标题,发电机());
            }
            赶上(例外五)
            {
                Console.WriteLine(
                    {0}:{1}  - > {2}称号,e.GetType(),e.​​Message);
            }
        }
    }
}
 
.NET Core 程序集复用技术 类型转移

当你运行这个程序,你得到绝对正确的结果:

  N4:HELLO FROM N4
PCL:HELLO FROM PCL
 

让我们添加AssemblyResolve事件到CurrentDomain在Program.Main:

  AppDomain.CurrentDomain.AssemblyResolve + =(_,A)=> {
    VAR文件名= Path.GetFullPath(
        新的AssemblyName(a.Name).Name点+.DATA);
    Console.WriteLine(探测{0}',文件名);
    返回
        File.Exists(文件名)
        ? Assembly.LoadFile(文件名)
        : 空值;
};
 

那么,它做什么,如果组件无法发现它试图从.DATA文件加载它。

让我们的应用程序文件夹,重命名为N4.dll到N4.data并运行C.exe。

 探测'C:\ XXX \ C \斌\调试\ N4.data
N4:HELLO FROM N4
PCL:HELLO FROM PCL
 

所以,经过AssemblyResolve最后加载N4.data和作品不如原来的。

让我们恢复N4.data到N4.dll重命名PCL.dll到PCL.data和...

 探测'C:\ XXX \ C \斌\调试\ PCL.data
N4:HELLO FROM N4
探测C:\ XXX \ C \斌\调试\ System.Core.data
探测C:\ XXX \ C \斌\调试\ System.Core.data
探测C:\ XXX \ C \斌\调试\ System.Core.data
PCL信息:System.IO.FileNotFoundException  - >无法加载文件或程序集System.Core程序,版本= 2.0.5.0,文化=中性公钥= 7cec85d7bea7798e,重定目标=是或它的一个依赖。该系统找不到指定的文件。
 

请注意,PCL组件加载就好了,问题是,它只是无法找到它的依赖(System.Core程序)了。

这就像Assembly.LoadFile(文件名)是,一个没有没有,如果加载的程序集是便携式的。

有没有人有这个问题?这儿还有没有人解决了这个问题?

您可以找到所有文件这里。

编辑: 感谢leppie迫使我去检查其他的选项。我其实是想确保我没有说谎,而我的回答是是的,是的,我试过。显然,这是值得一试。

从苏珊娜·库克的.NET CLR说明:

  

要小心 - 这些都是不一样的东西。

     

LoadFrom()经过融合,并且可以被重定向到另一个组件在不同的路径,但与相同的身份,如果一个是在LoadFrom上下文已加载。   的LoadFile()不会通过融合绑定在所有 - 装载机只是继续运行并装入正是*什么是来电者请求。它不使用任何负载或LoadFrom上下文。

解决方案

您可以将您的平台的 System.Core程序组件(如版本4.0.0.0用于.NET Framework 4.0 )从 AssemblyResolve 事件,当问及对 2.0.5.0 版本。

我通过载荷加载作为资源存储我的所有引用的程序集(字节[]),也未能解决 2.0.5.0 装配和我同时检索系统 System.Core程序 AppDomain.CurrentDomain.GetAssemblies()

First of all I need to emphasize that this is slightly different question than the one in this thread. Additionally, installing KB2468871 doesn't help.

I tried to simplify this problem as much as possible. In general it about loading PCL assemblies in Desktop application with Assembly.LoadFile(...).

Let's say there is a .NET 4.0 Console Application (called "C"). It references .NET 4.0 assembly (called "N4") and PCL assembly (called "PCL").

where N4 looks like this:

using System.Linq;

namespace N4
{
    public class ClassInN4
    {
        public static string Greet()
        {
            return new string(
                "hello from N4"
                .ToCharArray()
                .Select(char.ToUpper)
                .ToArray()
            );
        }
    }
}

PCL looks like this:

using System.Linq;

namespace PCL
{
    public class ClassInPCL
    {
        public static string Greet()
        {
            return new string(
                "hello from pcl"
                .ToCharArray()
                .Select(char.ToUpper)
                .ToArray()
            );
        }
    }
}

and C look like this:

using System;
using System.IO;
using System.Reflection;
using N4;
using PCL;

namespace C
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            Test();
            Console.ReadLine();
        }

        private static void Test()
        {
            Test("N4", ClassInN4.Greet);
            Test("PCL", ClassInPCL.Greet);
        }

        private static void Test(
            string title, 
            Func<string> generator)
        {
            try
            {
                Console.WriteLine(
                    "{0}: {1}", title, generator());
            }
            catch (Exception e)
            {
                Console.WriteLine(
                    "{0}: {1} -> {2}", title, e.GetType(), e.Message);
            }
        }
    }
}

When you run this application you get absolutely correct results:

N4: HELLO FROM N4
PCL: HELLO FROM PCL

Let's add AssemblyResolve event to CurrentDomain in Program.Main:

AppDomain.CurrentDomain.AssemblyResolve += (_, a) => {
    var fileName = Path.GetFullPath(
        new AssemblyName(a.Name).Name + ".data");
    Console.WriteLine("Probing '{0}'", fileName);
    return 
        File.Exists(fileName) 
        ? Assembly.LoadFile(fileName) 
        : null;
};

So, what it does if assembly cannot be found it tries to load it from ".data" file.

Let's go application folder and rename "N4.dll" to "N4.data" and run "C.exe".

Probing 'C:\xxx\C\bin\Debug\N4.data'
N4: HELLO FROM N4
PCL: HELLO FROM PCL

So it goes through AssemblyResolve and finally loads "N4.data" and works as good as original.

Let's revert "N4.data" to "N4.dll" and rename "PCL.dll" to "PCL.data" and...

Probing 'C:\xxx\C\bin\Debug\PCL.data'
N4: HELLO FROM N4
Probing 'C:\xxx\C\bin\Debug\System.Core.data'
Probing 'C:\xxx\C\bin\Debug\System.Core.data'
Probing 'C:\xxx\C\bin\Debug\System.Core.data'
PCL: System.IO.FileNotFoundException -> Could not load file or assembly 'System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes' or one of its dependencies. The system cannot find the file specified.

Please note that PCL assembly was loaded just fine, the problem is, it only can't find its dependencies (System.Core) anymore.

It's like Assembly.LoadFile(fileName) is-a no-no if loaded assembly is portable.

Did anyone have this problem? Did anyone solved this problem?

You can find all files here.

EDIT: Thanks to leppie for forcing me to check other options. I actually wanted to be sure that I'm not lying while I answer "Yeah, yeah, I tried". Apparently it was worth checking.

From Suzanne Cook's .NET CLR Notes:

Be careful - these aren't the same thing.

LoadFrom() goes through Fusion and can be redirected to another assembly at a different path but with that same identity if one is already loaded in the LoadFrom context. LoadFile() doesn't bind through Fusion at all - the loader just goes ahead and loads exactly* what the caller requested. It doesn't use either the Load or the LoadFrom context.

解决方案

You can return the System.Core assembly of your platform (e.g. version 4.0.0.0 for .NET Framework 4.0) from the AssemblyResolve event, when asked for the 2.0.5.0 version.

I am loading all my referenced assemblies stored as resources via Load(byte[]), which also fails to resolve the 2.0.5.0 assembly, and I retrieve both System and System.Core from AppDomain.CurrentDomain.GetAssemblies().