.NET Core Assembly.LoadFile на событии PostBuild - PullRequest
0 голосов
/ 26 июня 2018

Мне нужно сгенерировать typescript файлы из некоторых моих классов C # после сборки.

Я создал dotnet cli tool и добавил событие после сборки

dotnet tsgenerator "$(TargetPath)"

где $(TargetPath) - макрос, указывающий, например, D:\Test\bin\Release\netcoreapp2.0\my.dll

Далее я попытался загрузить сборку следующим образом:

public static void Main(string[] args)
{
    var dllPath = args[0]; // "D:\Test\bin\Release\netcoreapp2.0\my.dll"
    var assembly = Assembly.LoadFile(dllPath);
    var types = assembly.GetExportedTypes(); // Throws exception
}

Но я получил ReflectionTypeLoadException, который говорит Could not load file or assembly для некоторых сборок ссылок (например, Microsoft.AspNetCore.Antiforgery).

Как загрузить сборку для приложений .NET Core?

Ответы [ 3 ]

0 голосов
/ 27 июля 2018

Хорошо, вы можете загрузить сборку, но GetTypes() и GetExportedTypes() зависят от открытых классов в этой сборке, если у них есть внешние ссылки, вы получите это исключение.

Ответ: Это означает, что Types этой сборки зависит от другой сборки, к которой у текущего .NetCore нет доступа во время выполнения, поскольку он не может подключиться к другим зависимым сборкам

Решение:
Получите зависимости сборок DLL и скомпилируйте их все, затем загрузите каждую сборку итеративно, чтобы получить все ExportedTypes (т.е. общедоступные типы)

Код:

using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using Microsoft.Extensions.DependencyModel;// add this nuget

class Program
{
    static void Main(string[] args)
    {
        var asl = new AssemblyLoader();
        var asm = asl.LoadFromAssemblyPath(@"C:\temp\Microsoft.AspNetCore.Antiforgery.dll");
        try
        {

            var y = asm.GetExportedTypes();
            Console.WriteLine(y);
        }
        catch (Exception e1)
        {
            Console.WriteLine("Got exception at first attempt of GetExportedTypes ");
            Console.WriteLine("\t*********" + e1.Message + "**************");

            var deped = asl.CallForDependency(asm.GetName());

            try
            {
                Console.WriteLine("\n" + deped.ToString());
                Console.WriteLine("----------All Exported Types------------");

                foreach (var item in deped.ExportedTypes)
                {
                    Console.WriteLine(item);
                }
            }
            catch (Exception e2)
            {

                Console.WriteLine("Got exception at second attempt of GetExportedTypes ");
                Console.WriteLine("\t*********" + e2.Message + "**************");
            }

        }
        Console.ReadLine();

    }
}

public class AssemblyLoader :AssemblyLoadContext
{
    protected override Assembly Load(AssemblyName assemblyName)
    {
        var deps = DependencyContext.Default;
        var res = deps.CompileLibraries.Where(d => d.Name.Contains(assemblyName.Name)).ToList();
        var assembly = Assembly.Load(new AssemblyName(res.First().Name));
        return assembly;
    }

    public Assembly CallForDependency(AssemblyName assemblyName)
    {
        return this.Load(assemblyName);
    }
}

Выход:

Got exception at first attempt of GetExportedTypes
        *********Could not load file or assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. An operation is not legal in the current state. (Exception from HRESULT: 0x80131509)**************

Microsoft.AspNetCore.Antiforgery, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
----------All Exported Types------------
Microsoft.Extensions.DependencyInjection.AntiforgeryServiceCollectionExtensions
Microsoft.AspNetCore.Antiforgery.AntiforgeryOptions
Microsoft.AspNetCore.Antiforgery.AntiforgeryTokenSet
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException
Microsoft.AspNetCore.Antiforgery.IAntiforgery
Microsoft.AspNetCore.Antiforgery.IAntiforgeryAdditionalDataProvider
Microsoft.AspNetCore.Antiforgery.Internal.AntiforgeryFeature
Microsoft.AspNetCore.Antiforgery.Internal.AntiforgeryOptionsSetup
Microsoft.AspNetCore.Antiforgery.Internal.AntiforgerySerializationContext
Microsoft.AspNetCore.Antiforgery.Internal.AntiforgerySerializationContextPooledObjectPolicy
Microsoft.AspNetCore.Antiforgery.Internal.AntiforgeryToken
Microsoft.AspNetCore.Antiforgery.Internal.BinaryBlob
Microsoft.AspNetCore.Antiforgery.Internal.CryptographyAlgorithms
Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery
Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryAdditionalDataProvider
Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenGenerator
Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer
Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenStore
Microsoft.AspNetCore.Antiforgery.Internal.DefaultClaimUidExtractor
Microsoft.AspNetCore.Antiforgery.Internal.IAntiforgeryFeature
Microsoft.AspNetCore.Antiforgery.Internal.IAntiforgeryTokenGenerator
Microsoft.AspNetCore.Antiforgery.Internal.IAntiforgeryTokenSerializer
Microsoft.AspNetCore.Antiforgery.Internal.IAntiforgeryTokenStore
Microsoft.AspNetCore.Antiforgery.Internal.IClaimUidExtractor

Ссылка и пояснение к ReflectionTypeLoadException: Метод Assembly.GetTypes ()

ReflectionTypeLoadException

Сборка содержит один или несколько типов, которые не могут быть загружены. массив, возвращаемый свойством Types этого исключения, содержит тип объект для каждого типа, который был загружен и нуль для каждого типа, который мог не загружается, в то время как свойство LoaderExceptions содержит исключение для каждого типа, который не может быть загружен.

Примечания

Возвращенный массив содержит вложенные типы.

Если метод GetTypes вызывается в сборке и тип в этом сборка зависит от типа в сборке, которая не была загружен (например, если он происходит от типа во втором сборка), ReflectionTypeLoadException выбрасывается. Например, это может произойти, если первая сборка была загружена с ReflectionOnlyLoad или ReflectionOnlyLoadFrom методов, а второй сборка не была загружена. Это также может происходить с загруженными сборками. используя методы Load и LoadFile, если вторая сборка не может быть находится при вызове метода GetTypes.

Примечание

Если тип был перенаправлен в другую сборку, он не включается в возвращенном массиве. Для получения информации о пересылке типов см. Тип Экспедирование в Common Language Runtime.

Связано:

0 голосов
/ 27 июля 2018

Я нашел решение проблемы github . Сообщение от amits1995 и angelcalvasp .

Я добавил <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> в мой csproj и использую этот код для загрузки сборки:

public static class AssemblyLoader
{
    public static Assembly LoadFromAssemblyPath(string assemblyFullPath)
    {
        var fileNameWithOutExtension = Path.GetFileNameWithoutExtension(assemblyFullPath);
        var fileName = Path.GetFileName(assemblyFullPath);
        var directory = Path.GetDirectoryName(assemblyFullPath);

        var inCompileLibraries = DependencyContext.Default.CompileLibraries.Any(l => l.Name.Equals(fileNameWithOutExtension, StringComparison.OrdinalIgnoreCase));
        var inRuntimeLibraries = DependencyContext.Default.RuntimeLibraries.Any(l => l.Name.Equals(fileNameWithOutExtension, StringComparison.OrdinalIgnoreCase));

        var assembly = (inCompileLibraries || inRuntimeLibraries)
            ? Assembly.Load(new AssemblyName(fileNameWithOutExtension))
            : AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyFullPath);

        if (assembly != null)
            LoadReferencedAssemblies(assembly, fileName, directory);

        return assembly;
    }

    private static void LoadReferencedAssemblies(Assembly assembly, string fileName, string directory)
    {
        var filesInDirectory = Directory.GetFiles(directory).Where(x => x != fileName).Select(x => Path.GetFileNameWithoutExtension(x)).ToList();
        var references = assembly.GetReferencedAssemblies();

        foreach (var reference in references)
        {
            if (filesInDirectory.Contains(reference.Name))
            {
                var loadFileName = reference.Name + ".dll";
                var path = Path.Combine(directory, loadFileName);
                var loadedAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path);
                if (loadedAssembly != null)
                    LoadReferencedAssemblies(loadedAssembly, loadFileName, directory);
            }
        }
    }
}

Использование:

public static void Main(string[] args)
{
    var dllPath = args[0]; // "D:\Test\bin\Release\netcoreapp2.0\my.dll"
    var assembly = AssemblyLoader.LoadFromAssemblyPath(dllPath);
    var types = assembly.GetExportedTypes(); // No exceptions
}
0 голосов
/ 27 июля 2018

Попробуйте метод LoadFrom для загрузки в сборку, а не LoadFile:

public static void Main(string[] args)
{
    var dllPath = args[0]; // "D:\Test\bin\Release\netcoreapp2.0\my.dll"
    var assembly = Assembly.LoadFrom(dllPath);
    var types = assembly.GetExportedTypes(); // Throws exception
}

Вам также необходимо добавить те же ссылки, что и в файле ddl, в ваш текущий проект, чтобы определить типы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...