I'm trying to load an assembly, use Reflection to get all the class' inside that .dll, and then delete the .dll. However I am getting access denied exception when trying to delete the .dll. This is not due to access rights as I can delete the .dll if I do not load it first.
I've looked on MSDN, and apparently there is no way to "unload", but I'm hoping that there might be another way.
Assembly assembly;
assembly = Assembly.LoadFrom(filepath);
Type[] listOfAllClassInDll = assembly.GetTypes();
List<string> listOfAllClassNamesInDll = new List<string>();
foreach (Type classInDll in listOfAllClassInDll)
{
listOfAllClassNamesInDll.Add(classInDll.Name);
}
File.Delete(filepath);
Actually you can't do it straightforward..
There is why: http://blogs.msdn.com/b/jasonz/archive/2004/05/31/145105.aspx
But you can dynamically load your assembly in another AppDomain. Then when you don't need your assembly - you have to unload you AppDomain with loaded assembly.
Example there: https://bookie.io/bmark/readable/9503538d6bab80
Instead of using LoadFrom/LoadFile you can use Load with File.ReadAllBytes. Here you do not use assembly file directly but read it's content and use the read data. So, you are free to rename/delete the file.
Your code will then look like:
Assembly assembly;
assembly = Assembly.Load(File.ReadAllBytes(filepath));
Type[] listOfAllClassInDll = assembly.GetTypes();
List<string> listOfAllClassNamesInDll = new List<string>();
foreach (Type classInDll in listOfAllClassInDll)
{
listOfAllClassNamesInDll.Add(classInDll.Name);
}
File.Delete(filepath);
Hope this helps :)
Related
I have 2 assembly should be loaded from memory, I use the following code to implement it but it can't work. Help me, Thank you!
Assembly.Load(File.ReadAllBytes("b.dll"));
var assembly = Assembly.Load(File.ReadAllBytes("a.dll"));//a.dll referenced b.dll
var type = assembly.GetTypes().First(p => p.FullName == "Namespace1.Type1");
type.GetMethod("StaticMethod1", BindingFlags.Static | BindingFlags.Public).Invoke(null, new object[] { });//it throw an exception, can't load file or assembly b.dll
Using Assembly.Load to load an assembly from a byte array, loads the assembly but does not register it under its name in the Application Domain. In order to provide your own assembly from a byte array when the runtime is looking to load a specific assembly with a specific name, you implement the AppDomain.AssemblyResolve event.
See this question and the answer for example code.
I am trying to load a MSIL assembly using the following code :
string PathOfDll = "PathOfMsILFile (Dll)";
Assembly SampleAssembly;
SampleAssembly = Assembly.LoadFrom(PathOfDll);
At the end of this program I should delete this file :
File.Delete(PathOfDll);
It causes an error : 'System.UnauthorizedAccessException'
Additional information: Access to the path 'Path' is denied .
It is not relating to UAC it is just because I am loading the assembly at the start of program and when I wanna delete it manually it says that the file is in use in vshost.exe . So I say this just to show that it is for loading assemly !
So is there any way to get rid of it (something like Un-loading this assembly) ?
Note : I am writing a code to run Garbage Collector but this problem is still unsolved .
Thanks.
One possible way could be: Instead of LoadFrom, use Load as shown below.
Assembly asm = null;
try
{
asm = Assembly.Load(File.ReadAllBytes(path));
}
catch(Exception ex)
{
}
The accepted answer has memory leak problem. In deep, the assembly binary is loaded into memory and won't be released until your application exit.
I prefer the use of AppDomain which allows GC to clean up after using.
Sample code was provided by Rene de la garza at https://stackoverflow.com/a/6259172/7864940
In brief:
AppDomain dom = AppDomain.CreateDomain("some");
AssemblyName assemblyName = new AssemblyName();
assemblyName.CodeBase = pathToAssembly;
Assembly assembly = dom.Load(assemblyName);
//Do something with the loaded 'assembly'
AppDomain.Unload(dom);
I'm trying to make work the following code (it was decompiled):
foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
{
if ((!assembly.FullName.StartsWith("System") && !assembly.FullName.StartsWith("Microsoft")) && !assembly.FullName.StartsWith("mscorlib"))
{
list.Add(assembly.FullName);//keep the name of assembly.
}
}
foreach (string assemblyStirng in list)
{
var assembly = Assembly.Load(assemblyString);//here FileNotFoundException is thrown.
}
How is it possible? Dll is already in domain and Assembly.Load should return it.
Turn on assembly load logging with fusion log view:
Fusion Log View
It will tell you detailed information about why i can't find it.
Some reasons could be, that it was loaded from somewhere else than the application dir, or it did find different versions of the same dll
Could it be that Assembly.Load(string) takes an assembly name in it's long form (i.e. strongly named, maybe installed in the GAC), but you're giving it the short assembly name?
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 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.