Сборка .NET Core.LoadFile в событии PostBuild

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

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

dotnet tsgenerator "$(TargetPath)"

здесь $(TargetPath) указывает макросы, например, D:TestbinReleasenetcoreapp2.0my.dll

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

public static void Main(string[] args)
{
    var dllPath = args[0]; // "D:TestbinReleasenetcoreapp2.0my.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 ответов


Я нашел решение в выпуск 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
}

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

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

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

код:

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: сборка.Метод GetTypes ()

ReflectionTypeLoadException

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

Примечания

возвращаемый массив включает вложенные типы.

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

Примечание

если тип был перенаправлен в другую сборку он не включен в возвращаемом массиве. Сведения о пересылке типов см. В разделе Тип Переадресация в Common Language Runtime.

общие :


попробуйте метод 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 к вашему текущему проекту, чтобы определить типы.