"Не удалось загрузить файл или сборку" System.Core, Version = 2.0.5.0,... "при загрузке Portable Class Library динамически

Прежде всего, мне нужно подчеркнуть, что это немного другой вопрос, чем вопрос в этой теме. Кроме того, установка KB2468871 не помогает.

Я попытался максимально упростить эту проблему. В общем, о загрузке сборок PCL в приложении Desktop с Assembly.LoadFile(...).

Скажем, есть консольное приложение .NET 4.0 (называемое "C" ). Он ссылается на сборку .NET 4.0 (называемую "N4" ) и сборку PCL (называемую "PCL" ).

где N4 выглядит следующим образом:

using System.Linq;

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

PCL выглядит следующим образом:

using System.Linq;

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

и C выглядят так:

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

При запуске этого приложения вы получите абсолютно правильные результаты:

N4: HELLO FROM N4
PCL: HELLO FROM PCL

Добавьте дополнение AssemblyResolve к CurrentDomain в 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;
};

Итак, что он делает, если сборка не найдена, она пытается загрузить ее из файла ".data".

Отпустите папку приложения и переименуйте "N4.dll" в "N4.data" и запустите "C.exe".

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

Итак, он проходит через AssemblyResolve и, наконец, загружает "N4.data" и работает так же хорошо, как оригинал.

Верните "N4.data" в "N4.dll" и переименуйте "PCL.dll" в "PCL.data" и...

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.

Обратите внимание, что сборка PCL была загружена просто прекрасно, проблема в том, что она больше не может найти свои зависимости (System.Core).

Это похоже на Assembly.LoadFile(fileName) - нет-нет, если загруженная сборка переносима.

У кого-нибудь была эта проблема? Кто-нибудь решил эту проблему?

Вы можете найти все файлы здесь.

EDIT: Благодаря leppie заставляет меня проверять другие варианты. Я действительно хотел быть уверенным, что я не вру, пока я отвечаю: "Да, да, я пытался". По-видимому, стоит проверить.

От Заметки CLR для Suzanne Cook.NET:

Будьте осторожны - это не одно и то же.

LoadFrom() проходит через Fusion и может быть перенаправлен на другую сборку по другому пути, но с тем же идентификатором, если он уже загружен в контексте LoadFrom. LoadFile() вообще не связывается с Fusion - загрузчик просто идет вперед и точно загружает * то, что запросил вызывающий. Он не использует контекст Load или LoadFrom.

Ответ 1

Вы можете вернуть System.Core сборку вашей платформы (например, version 4.0.0.0 for .NET Framework 4.0) из события AssemblyResolve при запросе версии 2.0.5.0.

Я загружаю все мои ссылочные сборки, хранящиеся в виде ресурсов через Load(byte[]), также не удается разрешить сборку 2.0.5.0, и я извлекаю как System, так и System.Core из AppDomain.CurrentDomain.GetAssemblies().

Ответ 2

Я думаю, что вы получаете эти проблемы, потому что:

Вы получаете исключение, потому что у вас нет последних обновлений .NET.

http://www.paraesthesia.com/archive/2013/01/21/using-portable-class-libraries-update-net-framework.aspx

Обратите внимание на часть WSUS - вы можете подумать, что у вас есть последние обновления, но вы не заставляете сервер WSUS устареть.

Этот патч может помочь, но вам лучше всего получить все обновления .net:

http://support.microsoft.com/kb/2468871

(из комментария выше)

Попробуйте LoadFrom (...), а не LoadFile (...)/Load (byte []) и посмотрите, устраняет ли это вашу проблему?:)

Ответ 3

У меня была такая же проблема, и я получил следующее решение: вызовите следующий код перед динамической загрузкой сборки PCL.

Assembly.Load("System, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes");
Assembly.Load("System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes");

Если какая-либо другая зависимость отсутствует при загрузке сборки PCL, вам просто нужно добавить строку в код выше. По какой-то странной и непонятной причине это работает.