I have a user in production who is getting a ReflectionTypeLoadException while trying get the assembly types from an Outlook interop assembly. I need to code the application to better debug the problem but I cannot reproduce his issue so I have no way of testing the code to make sure it is giving me what I need.
I found this post: Error message 'Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.' which has sample code but I would like to debug through it to make sure it works for me and to see how it works.
Here is my code that throws. I have the actual assembly loaded. It is when I enumerate the types contained within that I get the exception:
Type t = assembly.GetTypes().Where(x => x.IsClass && x.Name.Equals("ApplicationClass")).FirstOrDefault();
Can anyone provide a sample or some insight into how I may simulate this problem so I can validate the code that I need to write?
Thanks.
I came across the same issue today. Here's what I came up with, based on one of the cases where I've hit this in the past:
var assemblyName = new AssemblyName("TestAssembly");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
var module = assemblyBuilder.DefineDynamicModule("MainModule");
var typeBuilder = module.DefineType(name: "TestType", attr: TypeAttributes.Public | TypeAttributes.Class);
// uncommenting this stops the error. Basically, GetTypes() seems to fail if the ModuleBuilder
// has an "unfinished" type
//typeBuilder.CreateType();
module.Assembly.GetTypes();
It seems all public members of System.Reflection.Assembly are virtual, so something like this may suit your purposes:
public class DodgyAssembly : Assembly
{
public override Type[] GetTypes()
{
throw new ReflectionTypeLoadException(new [] { typeof(Foo) }, new [] { new Exception() });
}
}
var assembly = new DodgyAssembly();
At the point where you create an instance of the outlook class, do you have a try block around it to get a stacktrace? also, does the application run as a client application? if so, the user may not have outlook installed?
You should be able to just throw a ReflectionTypeLoadException and use that to test. Obviously you should probably throw a more realistic example for your particular case, but this will simulate that exception type.
try
{
var test = 10;
throw new ReflectionTypeLoadException(new Type[] { test.GetType() }, new Exception[] { new FileNotFoundException() });
}
catch (ReflectionTypeLoadException ex)
{
var whatIsTheException = ex;
}
Related
I have consulted code on the website http://codeproject.com with the title "Loading Assemblies from Anywhere into a New AppDomain" of Marius Bancila, but I tested the error as in the attached picture, currently, I don't know resolve, hope you help, thank you.
Link Code
https://www.codeproject.com/Articles/453778/Loading-Assemblies-from-Anywhere-into-a-New-AppDom#_articleTop
Test
public class Program
{
[STAThread]
public static void Main()
{
var project = #"D:\Github\BeyConsPlugin\BeyConsProject\bin\x64\Debug\BeyConsRevitProject.dll";//Path to assembly
var manager = new AssemblyReflectionManager();
var success = manager.LoadAssembly(project, Guid.NewGuid().ToString());
if (success)
{
var result = manager.Reflect(project, (a) =>
{
return a.GetTypes();
});
Console.WriteLine(string.Join("\n", result.Select(x => x.Name)));
}
Console.ReadKey();
manager.UnloadAssembly(project);
}
}
Error
Assembly Resolver not Set
Marius's code has a bug in AssemblyReflectionProxy with regards that the Assembly Resolver is not set if you call LoadAssembly unlike Reflect<> which does.
Depending on how a child app domain is created, when loading assemblies it might only have access to the folder as specified during creation. If you need to assembly probe elsewhere for the assembly or its dependencies you need a Assembly Resolver. When .NET is looking for an assembly for a domain, it will call your handler as specified in the assemblie's ReflectionOnlyAssemblyResolve event. If not specified or if the resolver fails to locate the assembly, it will bubble up and throw a load fail exception.
I suggest you change the code from:
public class AssemblyReflectionProxy : MarshalByRefObject
{
private string _assemblyPath;
public void LoadAssembly(String assemblyPath)
{
try
{
_assemblyPath = assemblyPath;
Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
catch (FileNotFoundException)
{
// Continue loading assemblies even if an assembly
// cannot be loaded in the new AppDomain.
}
}
...to:
public class AssemblyReflectionProxy : MarshalByRefObject
{
private string _assemblyPath;
public void LoadAssembly(String assemblyPath)
{
try
{
AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve // <---- add me
+= OnReflectionOnlyResolve;
_assemblyPath = assemblyPath;
Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
catch (FileNotFoundException)
{
// Continue loading assemblies even if an assembly
// cannot be loaded in the new AppDomain.
}
}
You can see this in Sacha's original code that on which Marius based his.
Add Provision for Resolve Paths
The other problem with the code is that both assume that when loading one assembly, any dependent assemblies are in the same folder something that may not always be the case.
Alter AssemblyReflectionProxy to include a list of paths in which to probe:
public List<string> ResolvePaths { get; set; }
Then modify OnReflectionOnlyResolve to resemble the following:
private Assembly OnReflectionOnlyResolve(ResolveEventArgs args, DirectoryInfo directory)
{
Assembly loadedAssembly =
AppDomain.CurrentDomain.ReflectionOnlyGetAssemblies()
.FirstOrDefault(
asm => string.Equals(asm.FullName, args.Name,
StringComparison.OrdinalIgnoreCase));
if (loadedAssembly != null)
{
return loadedAssembly;
}
foreach (var tryFolder in ResolvePaths)
{
var asmName = args.Name.Split(',');
var assemblyPath = Path.Combine(tryFolder, asmName[0] + ".dll");
if (!File.Exists(assemblyPath))
return null;
return Assembly.ReflectionOnlyLoadFrom(assemblyPath);
}
}
What's in a name?
Both articles neglected to point out the fine print when using ReflectionOnlyLoad. Though Sacha did at least mention his code was for a "code generator" I can't help but wonder that both articles with their "Loading Assemblies....into a New AppDomain" are perhaps somewhat subject to interpretation.
The aim of ReflectionOnlyLoad is just that - for reflection. If you load an assembly via this method you cannot execute any code in it. Additionally and somewhat surprising at first to most assembly reflector programmers including me is that calling GetCustomAttributes will also fail (because it attempts to "instantiate" types in the assembly).
If you are writng your own plug-in system in which each plug-in has its own App Domain, the Assembly reflection and load methods are useful for different stages of the plug-in system loading pipeline:
first pass - use ReflectionOnlyLoad as a way to inspect the plug-in to see if it is valid; perhaps you want to run some security checks safe in the knowledge that none of the plug-ins code can run during this phase
second pass - after verifying the plug-in, you can safely Load/LoadFrom the assembly and execute the code
I'm trying to figure out what the limitations really means when deploying for iOS from Xamarin.
http://developer.xamarin.com/guides/ios/advanced_topics/limitations/
I was under the impression that you have no JIT and thus any MakeGenericMethod or MakeGenericType would NOT work as that would require JIT compilation.
Also I understood that when running on the simulator, these restrictions does not apply since the simulator is not running in the full AOT (Ahead of Time) mode.
After setting up my Mac so that I could deploy to my phone, I would except the following test to fail when running on the actual device (iPhone).
[Test]
public void InvokeGenericMethod()
{
var method = typeof(SampleTests).GetMethod ("SomeGenericMethod");
var closedMethod = method.MakeGenericMethod (GetTypeArgument());
closedMethod.Invoke (null, new object[]{42});
}
public static void SomeGenericMethod<T>(T value)
{
}
private Type GetTypeArgument()
{
return typeof(int);
}
The thing is that completes successfully and I can't really understand why. Does not this code require JIT compilation?
In an effort to "make it break" , I also did a test with MakeGenericType.
[Test]
public void InvokeGenericType()
{
var type = typeof(SomeGenericClass<>).MakeGenericType (typeof(string));
var instance = Activator.CreateInstance (type);
var method = type.GetMethod ("Execute");
method.Invoke (instance, new object[]{"Test"});
}
public class SomeGenericClass<T>
{
public void Execute(T value)
{
}
}
How can this work when there is no JIT?
Am I missing something ?
In order to make the code fail go to iOS project options, tab "iOS Build" and change the "Linker Behavior:" to "Link all assemblies". Running the code will result in Exception and it will be of type default constructor for type XXX was not found.
Now, make a reference to the SomeGenericClass{string} in your code and the method will run just fine. The two added lines cause the compiler to include SomeGenericClass{string} in the binary. Note that the lines can be anywhere in the application that is compiled into the binary, they don't have to be in the same function.
public void InvokeGenericType()
{
// comment out the two lines below to make the code fail
var strClass = new SomeGenericClass<string>();
strClass.Execute("Test");
var type = typeof(SomeGenericClass<>).MakeGenericType (typeof(string));
var instance = Activator.CreateInstance (type);
var method = type.GetMethod ("Execute");
method.Invoke (instance, new object[]{"Test"});
}
I've written a plugin manager so
public class WeinCadPluginManager : NinjectModule, IEnableSerilog
{
public override void Load()
{
var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().CodeBase);
var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
var dirPath = Path.GetDirectoryName(codeBasePath);
Debug.Assert(dirPath != null, "dirPath != null");
var path = dirPath;
var types = Directory
.GetFiles(path, "*.dll")
.Select (Assembly.LoadFile)
.SelectMany (assembly =>
{
try
{
return assembly.GetExportedTypes();
}
catch (Exception e)
{
this.Serilog()
.Error
(e, "Failed to load assembly {assembly}", assembly);
return new Type[]
{
};
}
})
.Where(type=>typeof(IWeinCadPlugin).IsAssignableFrom(type))
.ToList();
foreach (var assembly in types)
{
Kernel.Bind<IWeinCadPlugin>().To(assembly).InSingletonScope();
}
}
}
Now this pretty much duplicates
Kernel.Load("*.dll")
except if there are any errors exporting the types from an assembly then Kernel.Load crashes with no error handling possible. I wouldn't want the failure to load a single plugin assembly to crash my app. Is my solution the only viable way or does Ninject have some error handling available?
I think a try { } catch { } around each Kernel.Load("specificplugin.dll") should suffice.
You would still have to find all the assemblies yourself, but would have to write less code.
var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().CodeBase);
var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
var dirPath = Path.GetDirectoryName(codeBasePath);
var dllPaths = Directory.GetFiles(dirpath, "*.dll");
foreach(string dllPath in dllPaths)
{
try
{
kernel.Load(dllPath);
}
catch (Exception e)
{
this.Serilog()
.Error(e, "Failed to load assembly {assembly}", assembly);
}
}
Drawback: ninject must be adding the binding to the kernel either on .Bind() or on .To(..), because all the rest of the fluent syntax methods are optional. So if there would be an exception in the .When(), .InScope(),.. any other optional method, you would be left with a non-complete binding and thus, most likely, a faulty software.
(However i suspect that most errors will not materialize when creating the binding, but rather when activating the binding. And you are not protected against that.)
As far as i know there is no way to remove bindings from ninject once you've added them. Except for the .Rebind() - but that is always replacing a binding with a different one.
So no, i don't think there's something like "rollback on exception".
So we must be looking for an alternative solution. There is one: child kernels. https://github.com/ninject/ninject.extensions.childkernel
Load each plugin into it's own child kernel. in case the fooplugin.dll load fails, dispose the child kernel. In case it works.. well you're good to go! :)
This also has the advantage that plugin's can't influence one another. Imagine two plugins would do IBindingRoot.Bind<string>().ToConstant("some constant") ;-)
(please note that i haven't tested whether disposing the child kernel before the parent kernel works "as expected", so you should test it out first. Simple enough, right?)
I have developped a custom XMLDeserializer which uses reflection to deserialize the content of my game (.xml). But I have an error that i don't figure it out when the content pipeline is compiling:
Error 1 Building content threw MethodAccessException: Attempt by
security transparent method
'DynamicClass.ReflectionEmitUtils(System.Object)' to access security
critical method 'System.Reflection.Assembly.get_PermissionSet()'
failed.
Assembly 'mscorlib, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089' is marked with the
AllowPartiallyTrustedCallersAttribute, and uses the level 2 security
transparency model. Level 2 transparency causes all methods in
AllowPartiallyTrustedCallers assemblies to become security transparent
by default, which may be the cause of this exception.
The error doesn't occur if I comment out this code :
// Add item to the collection
if (typeof(IList).IsAssignableFrom(collectionType))
{
collectionType.GetMethod("Add").Invoke(collectionObject, new[] { itemObject });
}
else if (typeof(IDictionary).IsAssignableFrom(collectionType))
{
collectionType.GetMethod("Add").Invoke(collectionObject, new[] { itemType, itemObject });
}
It seems that my assembly does not have the permission to call code in mscorlib assembly.
If i call my method in a console application, it works.
Can you help me?
Thanks
Since IList and IDictionary are generic, maybe you are not locating the correct method, or are trying to pass the wrong types to them? Their Add methods will be strongly typed to their generic type. You might also be finding the wrong Add overload since you did not specify the parameter types. You might wish to do something like:
// Add item to the collection
if (typeof(IList).IsAssignableFrom(collectionType)) {
var addMethod = collectionType.GetMethod("Add", new[] { itemObject.GetType() });
if (addMethod == null)
throw new SerializationException("Failed to find expected IList.Add method.");
addMethod.Invoke(collectionObject, new[] { itemObject });
} else if (typeof(IDictionary).IsAssignableFrom(collectionType)) {
var addMethod = collectionType.GetMethod("Add", new[] { typeof(Type), itemObject.GetType()}
if (addMethod == null)
throw new SerializationException("Failed to find expected IDictionary.Add method.");
addMethod.Invoke(collectionObject, new[] { itemType, itemObject });
}
I've searched high and low, but I can't come up with a solution for this.
I need to get all the interface types from an assembly with code like this:
IEnumerable<Type> interfaces = _assembly.GetTypes().Where(x => x.IsInterface);
The problem is, for certain assemblies I run into the following error:
Unable to load one or more of the
requested types. Retrieve the
LoaderExceptions property for more
information.
I'm completely clear on why this happens (dependant assemblies are not loaded), and how it can be worked around if I want to troubleshoot a specific assembly. In my case, I don't know the assembly up front (the user will select it).
What I'd like to know is whether there is any way to allow the code to continue past any types that can't be retrieved, and still pull the ones that don't fail.
It looks like this is a vexing API for which the exception cannot be avoided (as far as I know).
Try something like this:
IEnumerable<Type> interfaces;
try
{
interfaces = _assembly.GetTypes().Where(x => x.IsInterface);
}
catch (ReflectionTypeLoadException ex)
{
interfaces = ex.Types.Where(x => x != null && x.IsInterface);
}
UPDATE
Actually, this is so ugly that I would probably hide it somewhere. This must be a very old part of the .NET Framework, because I’m pretty sure they wouldn't design it like this nowadays.
private static IEnumerable<Type> GetTypesSafely(Assembly assembly)
{
try
{
return assembly.GetTypes();
}
catch(ReflectionTypeLoadException ex)
{
return ex.Types.Where(x => x != null);
}
}
...
IEnumberable<Type> interfaces = GetTypesSafely(_assembly).Where(x => x.IsInterface);
If you think you'll be doing this very often, then an extension method might be more appropriate.
Handle the exception in another method that takes the place of the lambda expression and catches the exception. You could also have the exceptions accumulate in some global object for inspection later.
IEnumerable<Type> interfaces = _assembly.GetTypes().Where(IsInterface);
List<string> Messages = new List<string>();
private bool IsInterface(Type x)
{
try { return x.IsInterface; }
catch (Exception e)
{
Messages.Add(e.Message);
}
return false;
}