构建后,我需要从某些C#类生成typescript
文件。
我创建了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应用程序加载程序集?
答案 0 :(得分:5)
我在github issue找到了解决方案。 amits1995和angelcalvasp的消息。
我在我的csproj中添加了<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
,并使用以下代码加载了程序集:
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
}
答案 1 :(得分:1)
您可以加载程序集,但是GetTypes()
和GetExportedTypes()
依赖于该程序集中的公共类,如果它们具有外部引用,则会出现此异常。
答案:
这意味着该程序集的Types
依赖于当前.NetCore在运行时无法访问的其他程序集,因为它无法连接到其他相关程序集
解决方案:
获取DLL程序集的依赖关系并将其全部编译,然后迭代加载每个程序集以获取所有ExportedTypes(即公开可见的Types)
代码:
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 Method ()
ReflectionTypeLoadException
程序集包含一种或多种无法加载的类型。的 此异常的
Types
属性返回的数组包含一个Type 每种加载类型的对象,每种可能加载的类型为nullLoaderExceptions
属性包含一个 每种无法加载的类型的异常。备注
返回的数组包含嵌套类型。
如果在程序集和其中的类型上调用了
GetTypes
方法 程序集依赖于尚未存在的程序集中的类型 已加载(例如,如果它来自第二个类型 集合),则抛出ReflectionTypeLoadException
。例如这个 如果第一个装配件中装有ReflectionOnlyLoad
或ReflectionOnlyLoadFrom
方法,第二种 程序集未加载。加载程序集时也可能发生 如果不能使用第二个程序集,则使用Load和LoadFile
方法 在调用GetTypes
方法时位于。注意
如果类型已转发到另一个程序集,则不包含 在返回的数组中。有关类型转发的信息,请参见类型 在
Common Language Runtime
中转发。
已链接:
答案 2 :(得分:0)
尝试使用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文件中的相同引用添加到当前项目中,以便定义类型。