I have written the following Utility class to get an instance of any class of name "className".
public class AssemblyUtils
{
private AssemblyUtils()
{
}
public static T GetInstance<T>(string assemblyName, string className)
{
T classInstance = default(T);
System.Reflection.Assembly assembly = System.Reflection.Assembly.Load(assemblyName);
object o = assembly.CreateInstance(className);
if (o is T)
{
classInstance = (T)o;
}
else
{
o = null;
}
return classInstance;
}
I have called this like:
IMyInterface ins = AssemblyUtils.GetInstance<IMyInterface>(#"MyNamespace.DA.dll", "MyClassDA");
But I am getting the following error message:
Could not load file or assembly 'MyNamespace.DA.dll' or one of its dependencies. The system cannot find the file specified.
Note that, I called the AssemblyUtils.GetInstance() from separate assemblies which are in the same sln.
How can I resolve the assembly path???
My guess is that it cannot find assembly because it's not in the same folder and not in the GAC, or other directories where the system is looking for.
You need either move them in the same folder where an executing assembly. You can change the folder where assembly is loaded from by using AppDomainSetup.PrivateBinPath Property.
I think, the assembly you want to load (MyNamespace.DA.dll) is dependent to another assembly which is not located in you folder you're looking for. Copy the dependent assemblies into the folder where you located MyNamespace.DA.dll assembly.
Check your bin\Debug folder, is the MyNamespace.DA.dll in that folder? If not you're going to have to move it in there manually. Maybe add a postcondition so that its copied in automatically. Also try using the full assembly strong name.
Also JMSA, how about some upvotes and accepting answers on your other thread?
As Vadim mentioned Assembly.Load will only look in a limited set of places. Assembly.LoadFrom might be a better bet for you. It takes a path (with filename) to the assembly.
Assembly.Load works off the assembly name, not the path.
Related
As a followup to this question I have now come to the problem of being able to get the Type of a type that is defined by the user in his own solution. Using the standard mscorlib types, everything works.
The question is very easy: how can I get this type from an assembly that I will only know at runtime?
As described in the comments here:
Also, what do you mean by "extracting the type"? You mean getting the Reflection type? There's no good helper, partly because (typically) you can never assume the type you're compiling against is creatable at runtime. There's a strong (and often overlooked) distinction between "compile time" and "run time", and it's rare to bridge them.
Or here on the previous question:
Well, so getting a Type for TypeInfo, naming issues aside, is a tricky problem. It assumes you have an assembly that can be loaded and found. When you do a build, the compiler might be loading reference assemblies that themselves can't be loaded as "normal" assemblies. Even if they are, you might have to hook AppDomain.AssemblyResolve to locate your references, and whatever assembly you built.
"Build" and "runtime" are really different domains, and crossing from one to the other is poorly defined, at best. I assume here that you really need a System.Type because you're using some other reflection API, or trying to then load that type and execute code from it.
I have followed the approach as laid out here and implemented it as such in my Analyzer:
private static Dictionary<string, Assembly> _assemblies = new Dictionary<string, Assembly>();
var containingAssembly = semanticModel.GetSymbolInfo(argument)
.Symbol
.ContainingAssembly;
if (!_assemblies.TryGetValue(containingAssembly.ToString(), out Assembly result))
{
var newAssembly = Assembly.Load(containingAssembly.ToString());
_assemblies.Add(containingAssembly.ToString(), newAssembly);
}
var currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += ResolveAssemblies;
private Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
_assemblies.TryGetValue(args.Name, out Assembly result);
return result;
}
But this hasn't made a difference, I keep getting
The User Diagnostic Analyzer 'DiagnosticTools.Collections.ElementaryMethodsNotOverriden.ElementaryMethodsNotOverridenAnalyzer' threw an exception with message 'Could not load file or assembly 'RoslynTester, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.'.
Using fuslogvw.exe gives me this log information which boils down to
LOG: All probing URLs attempted and failed.
After searching for the .dll and .exe version in a few subfolders of /Common7/IDE/.
As context to clarify why I'm doing this: I want to check every type that is used in a collection and verify that it overrides both Equals and GetHashCode. To determine this I have a "classic" reflection extension method that checks this for me:
public static bool IsOverridden(this MethodInfo method)
{
return method.GetBaseDefinition().DeclaringType != method.DeclaringType;
}
So should Roslyn have a way to verify this itself that would make it so that I don't have to use classic reflection at all, then this would also be fine.
Update:
When I use this code as provided by MSDN, I get an "invalid parameter" exception inside Visual Studio but fuslogvw still shows a "file not found" error message. What causes this discrepancy?
private Assembly ResolveAssemblies(object sender, ResolveEventArgs args)
{
Assembly MyAssembly, objExecutingAssemblies;
string strTempAssmbPath = "";
objExecutingAssemblies = Assembly.GetExecutingAssembly();
AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();
foreach (AssemblyName strAssmbName in arrReferencedAssmbNames)
{
if (strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(",")) == args.Name.Substring(0, args.Name.IndexOf(",")))
{
strTempAssmbPath = #"C:\Users\Jeroen\Documents\Visual Studio 2013\Projects\RoslynTester\RoslynTester\bin\Debug\" + args.Name.Substring(0, args.Name.IndexOf(",")) + ".exe";
break;
}
}
MyAssembly = Assembly.LoadFrom(strTempAssmbPath);
return MyAssembly;
}
I'm assuming you've already found out (programmatically) which class are contained in your collection. You don't really need reflection to accomplish what you want. With Roslyn you can check if a class overrides the Equals method with this SyntaxWalker:
public class FindOverrides : CSharpSyntaxWalker
{
public override void VisitMethodDeclaration(MethodDeclarationSyntax node)
{
base.VisitMethodDeclaration(node);
if (node.Identifier.Text == "Equals"
&& node.Modifiers.Any(m => m.Text == "override"))
{
// found an override of Equals()
}
}
}
To (blindly) check every method of every type in a given solution it can be used like this:
var syntaxRoots =
from project in solution.Projects
from document in project.Documents
select document.GetSyntaxRootAsync().Result;
foreach (var root in syntaxRoots)
new FindOverrides().Visit(root);
There is at least one omission (if that's a valid case for you): my code above won't find if a base class of a given type is overriding Equals().
I've found a lot of similar questions but couldn't find any solution.
I have following code:
string file = "c:\\abc.dll";
AppDomainSetup ads = new AppDomainSetup();
ads.PrivateBinPath = Path.GetDirectoryName(file);
AppDomain ad2 = AppDomain.CreateDomain("AD2", null, ads);
ProxyDomain proxy = (ProxyDomain)ad2.CreateInstanceAndUnwrap(typeof(ProxyDomain).Assembly.FullName, typeof(ProxyDomain).FullName);
Assembly asm = proxy.GetAssembly(file); // exception File.IO assembly not found is thrown here after succesfully running the funktion GetAssembly.
public class ProxyDomain : MarshalByRefObject
{
public Assembly GetAssembly(string assemblyPath)
{
try
{
Assembly asm = Assembly.LoadFile(assemblyPath);
//...asm is initialized correctly, I can see everything with debugger
return asm;
}
catch
{
return null;
}
}
}
The most Interesting thing that then my GetAssembly funktion returns some other type, even my custom serializable class, everything is fine. Does someone know what I'm missing? Or It's just impossible to return loaded assembly to another domain?
Thank you
I imagine File.IO is sitting in your main application's bin directory? If so, your abc.dll will not know where to find it (unless your main application is also sitting in C:\\).
You need to do one of
Bind to the AppDomain.AssemblyResolve event and manually load the referenced dll
Change the AppDomainSetup's base directory (which is one of the places .NET knows to look for dlls)
Install File.IO to the GAC (which is another one of the places .NET knows to look for dlls)
Add the location of File.IO to your AppDomainSetup's private probing path (which is another one of the places .NET will try to look for dlls).
Iterating through a directory for *.dll files, find them and create an Assembly reference for each file.
Once I have a reflected object, I iterate through all the types available in each, from which I'd like to get the custom attributes for each type in the collection:
string[] files = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory + "Methods", "*.dll");
foreach (string s in files)
{
Assembly asm = Assembly.LoadFile(s);
Type[] asmTypes = asm.GetTypes();
bool isCorrect = false;
foreach (Type type in asmTypes)
{
1. var customAttribs = type.GetCustomAttributes(typeof(BaseModelAttribute), false);
}
}
[Update] : exception raised at line # 1
This code works all the way up to the foreach...loop when I get an exception saying that the file could not be found, which is weird as I created an Assembly reference from the file higher up in the code block (not mentioned in code).
[Update]: Erno was correct in in assuming a reference could not be established. Base, for some reason needs to be defined outside of the reference pool (being in the bin directory) even though it's not actually needed by the application. Does not makes sense to me, but it works. Thanks.
When .NET is not able to find a file it probably is trying to load an assembly that the currently reflected assembly is dependent on.
You can use Fuslogvw.exe (SDK) to find out what assembly is being searched for.
I'm making a little tool to analyze code dependencies recursively. I found a problem: if I try to get a member of a class whose signature contains a reference to another dll the method fails. For example, if I have a simple class in Main.exe
public class MainClass {
public MainClass () {
foo();
}
public ContainedClass GetPublicClass () {
return new ContainedClass ();
}
}
and ContainedClass is defined in other file refers.dll, when I try the following code it throw a FileNotFoundException in met3.ReturnType() method cause .net not find refers.dll.
Assembly assem = Assembly.LoadFile(#"D:\dir\Main.exe");
Type typ = assem.GetType ("MultipleReference.MainClass");
MethodInfo met3 = typ.GetMethod ("GetPublicClass");
met3.ReturnType.ToString ();
Is there any way to indicate where to search the dll?
Thanks in advance and sorry for my English.
Use LoadFrom instead of LoadFile because it will also resolve and load dependent assemblies. Quoting the documentation:
Use the LoadFile method to load and
examine assemblies that have the same
identity, but are located in different
paths. LoadFile does not load files
into the LoadFrom context, and does
not resolve dependencies using the
load path, as the LoadFrom method
does. LoadFile is useful in this
limited scenario because LoadFrom
cannot be used to load assemblies that
have the same identities but different
paths; it will load only the first
such assembly.
We implement a plugin framework for our application and load plugin assemblies using Assembly.Loadfrom. We then use GetTypes() and further examine the types with each plugin file for supported Interfaces.
A path for the plugins is provided by the user and we cycle through each of the files in the folder to see if it (the plugin) supports our plugin interface. If it does, we create an instance, if not we move onto the next file.
We build two versions of software from the one code base (appA_1 and appA_2).
Loading the plugins works well when the plugins are loaded by the application that was built at the same time as the plugin file. However if we build appA_2 and point to the plugin folder of appA_1, we get an exception when GetTypes() is called.
A basic version of our code is;
var pluginAssembly = Assembly.LoadFrom(FileName);
foreach (var pluginType in pluginAssembly.GetTypes())
{
We get a "ReflectionTypeLoadException" exception.
This is concerning because we want our application to be able to load the types of any plugin, built by anyone. Is there something we are missing?
EDIT:
After iterating through the LoaderExceptions we have discovered that there is a single file libPublic.dll that generates a System.IO.FileNotFoundException exception. The strange thing is that this file resides in the application directory and the plugin is referenced to the project file.
EDIT 2:
In the exception log we find the following
"Comparing the assembly name resulted in the mismatch: Revision Number"
A few things:
Make sure you don't have duplicate assemblies in the plugin directory (i.e. assemblies that you're already loading in your main app from your app directory.) Otherwise, when you load your plugin, it may load an additional copy of the same assembly. This can lead to fun exceptions like:
Object (of type 'MyObject') is not of type 'MyObject'.
If you're getting the exception when instantiating a type, you may need to handle AppDomain.AssemblyResolve:
private void App_Startup(object sender, StartupEventArgs e)
{
// Since we'll be dynamically loading assemblies at runtime,
// we need to add an appropriate resolution path
// Otherwise weird things like failing to instantiate TypeConverters will happen
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
}
private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
var domain = (AppDomain) sender;
foreach (var assembly in domain.GetAssemblies())
{
if (assembly.FullName == args.Name)
{
return assembly;
}
}
return null;
}
I realize it's a bit strange to have to tell the CLR that, in order to resolve an assembly, find the assembly with the name we're using to resolve, but I've seen odd things happen without it. For example, I could instantiate types from a plugin assembly, but if I tried to use TypeDescriptor.GetConverter, it wouldn't find the TypeConverter for the class, even though it could see the Converter attribute on the class.
Looking at your edits, this is probably not what's causing your current exception, though you may run into these issues later as you work with your plugins.
Thanks to this post I could solve the ReflectionTypeLoadException that I was getting in a UITypeEditor. It's a designer assembly (a winforms smart-tag used at design-time) of a custom class library, that scan for some types.
/// <summary>
/// Get the types defined in the RootComponent.
/// </summary>
private List<Type> getAssemblyTypes(IServiceProvider provider)
{
var types = new List<Type>();
try
{
IDesignerHost host = (IDesignerHost)provider.GetService(typeof(IDesignerHost));
ITypeResolutionService resolution = (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService));
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
{
foreach (var assembly in ((AppDomain)sender).GetAssemblies())
{
if (assembly.FullName == args.Name)
{
return assembly;
}
}
return null;
};
Type rootComponentType = resolution.GetType(host.RootComponentClassName, false);
types = rootComponentType.Assembly.GetTypes().ToList();
}
catch
{
}
return types;
}
You are getting an assembly version mismatch. Since your plugins refer to this libPublic.dll, you must version it carefully and in particular not bump its revision/build/etc. numbers at every compile.