I'm using a method to load a dll on an AssemblyResolve event. It's not quite working the way I want it to. Here's some code:
in my form load:
var a = AppDomain.CurrentDomain;
a.AssemblyResolve += (object sender, ResolveEventArgs args) => LoadDLL(sender, args, anArg);
LoadDLL:
public Assembly LoadDLL(object sender, ResolveEventArgs agrs, bool anArg){
//Let's just ignore anArg, it doesn't affect anything related to the problem
asseblyPath = #"XXX";//path to my dll
return Assembly.LoadFrom(assemblyPath);
}
So that's all well and good. I set Copy Local to false for my DLL so the AssemblyResolve event is called and I can load the desired version of my DLL.
One strange thing that is happening is this: After running this code, my code tries to access a public variable from a class containing global constant values (this class should be in my DLL).
public class GCV{
public GCV(){}
public string value1= "asdf";
}
Unfortunately, when I'm in debug mode, GCV.value1 is set to null when it clearly has a value in the class definition. This is one symptom that I can describe here, hopefully enough to diagnose the problem?
Thanks!
It seems that in debug the version loaded differ from the one it load in release. Try to look in the Output folder when debugging, and look for the Loaded .... to find your dll. This should point to a different version that the one you expect.
Related
I have a command line application where I want to load some DLLs at some paths outside my application directory. I can successfully do this by adding my own ResolveEventHandler. However, I then get unwanted output in the console like this:
Checking for existing AssemblyResolve handler
Removed existing AssemblyResolve handler
How can I suppress this output?
Here's my current code:
static Assembly LoadPrereq(object sender, ResolveEventArgs args)
{
if (args.Name.StartsWith("DebugDiag.DotNet"))
return Assembly.LoadFile("C:\\Program Files\\DebugDiag\\DebugDiag.DotNet.dll");
return null;
}
...
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(LoadPrereq);
Maybe this might help Console.SetOut(TextWriter)
Sets the Out property to target the TextWriter object.
For which, you could call the following to disable it
Console.SetOut(TextWriter.Null);
You might be able save the original with Console.Out so it can be re-enabled again
Gets the standard output stream.
Note : This is untested, and only found via the documentation
I apologize in advance if the title doesn't make sense. I'm very new to appdomains and assembly loading and don't really know how to state what I'm trying to ask.
I have been fiddling around with loading embedded DLLs into an application during runtime and I can't seem to figure out why it works one way but not the other. It seems like if you try to load DLLs (from a byte array) into the current appdomain, any objects/threads created after that will be able to resolve references against the newly loaded library, however objects in the original context will not resolve against the newly loaded library.
Here is my example library that will be loaded from as an embedded resource during runtime (requires a reference to the WPF PresentationFramework.dll for MessageBox):
namespace LoaderLibrary
{
public class LoaderLibrary
{
public static void Test()
{
System.Windows.MessageBox.Show("success");
}
}
}
In my console app .csproj file I manually add the following embedded resource for that project and include a project reference to LoaderLibrary as well:
<ItemGroup>
<EmbeddedResource Include="..\LoaderLibrary\bin\$(Configuration)\LoaderLibrary.dll">
<LogicalName>EmbeddedResource.LoaderLibrary.dll</LogicalName>
</EmbeddedResource>
</ItemGroup>
Here is the code for my console app that loads that library (requires a project reference to the LoaderLibrary csproj) ALSO: Need to set CopyLocal to false for LoaderLibrary reference:
namespace AssemblyLoaderTest
{
class Program
{
static void Main(string[] args)
{
EmbeddedAssembly.Load("EmbeddedResource.LoaderLibrary.dll");
System.AppDomain.CurrentDomain.AssemblyResolve += (s, a) => { return EmbeddedAssembly.Get(a.Name); };
var app = new TestApp();
}
}
public class TestApp
{
public TestApp()
{
LoaderLibrary.LoaderLibrary.Test();
}
}
public class EmbeddedAssembly
{
static System.Collections.Generic.Dictionary<string, System.Reflection.Assembly> assemblies = new System.Collections.Generic.Dictionary<string, System.Reflection.Assembly>();
public static void Load(string embeddedResource)
{
using (System.IO.Stream stm = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedResource))
using (var mstream = new System.IO.MemoryStream())
{
stm.CopyTo(mstream);
var assembly = System.Reflection.Assembly.Load(mstream.ToArray());
assemblies.Add(assembly.FullName, assembly);
return;
}
}
public static System.Reflection.Assembly Get(string assemblyFullName)
{
return (assemblies.Count == 0 || !assemblies.ContainsKey(assemblyFullName)) ? null : assemblies[assemblyFullName];
}
}
}
This code is able to successfully load and execute the LoaderLibrary.LoaderLibrary.Test() function.
My question is why does the following not work?
static void Main(string[] args)
{
EmbeddedAssembly.Load("EmbeddedResource.LoaderLibrary.dll");
System.AppDomain.CurrentDomain.AssemblyResolve += (s, a) => { return EmbeddedAssembly.Get(a.Name); };
LoaderLibrary.LoaderLibrary.Test(); // very unhappy line of code
}
This also doesn't work:
static void Main(string[] args)
{
EmbeddedAssembly.Load("EmbeddedResource.LoaderLibrary.dll");
System.AppDomain.CurrentDomain.AssemblyResolve += (s, a) => { return EmbeddedAssembly.Get(a.Name); };
var app = new TestApp();
LoaderLibrary.LoaderLibrary.Test(); // very unhappy line of code
}
Big thanks to Hans Passant and dthorpe for explaining what was happening.
I found dthorpe's great explanation on how the JIT compiler works here: C# JIT compiling and .NET
To quote dthorpe here:
Yes, JIT'ing IL code involves translating the IL into native machine
instructions.
Yes, the .NET runtime interacts with the JIT'ed native machine code,
in the sense that the runtime owns the memory blocks occupied by the
native machine code, the runtime calls into the native machine code,
etc.
You are correct that the .NET runtime does not interpret the IL code
in your assemblies.
What happens is when execution reaches a function or code block (like,
an else clause of an if block) that has not yet been JIT compiled into
native machine code, the JIT'r is invoked to compile that block of IL
into native machine code. When that's done, program execution enters
the freshly emitted machine code to execute it's program logic. If
while executing that native machine code execution reaches a function
call to a function that has not yet been compiled to machine code, the
JIT'r is invoked to compile that function "just in time". And so on.
The JIT'r doesn't necessarily compile all the logic of a function body
into machine code at once. If the function has if statements, the
statement blocks of the if or else clauses may not be JIT compiled
until execution actually passes through that block. Code paths that
have not executed remain in IL form until they do execute.
The compiled native machine code is kept in memory so that it can be
used again the next time that section of code executes. The second
time you call a function it will run faster than the first time you
call it because no JIT step is necessary the second time around.
In desktop .NET, the native machine code is kept in memory for the
lifetime of the appdomain. In .NET CF, the native machine code may be
thrown away if the application is running low on memory. It will be
JIT compiled again from the original IL code the next time execution
passes through that code.
With the information from that question, and the information from Hans Passant, it is very clear what is happening:
The JIT compiler attempts to convert the entire entry point code
block (in this case my Main() function) into native code. This
requires that it resolve all references.
The embedded assembly LoaderLibrary.dll has NOT been loaded into the
AppDomain yet because the code that does this is defined in the
Main() function (and it can't execute code that hasn't been compiled).
The JIT compiler attempts to resolve the reference to
LoaderLibrary.dll by searching the AppDomain, Global Assembly Cache,
App.config/Web.config, and probing (environment PATH, current
working directory, etc.) More info on this can be found in the MSDN
article here: How the Runtime Locates Assemblies
The JIT compiler fails to resolve the reference to
LoaderLibrary.LoaderLibrary.Test(); and results in the error
Could not load file or assembly or one of its dependencies
The way to get around this as suggested by Hans Passant is to load your assemblies in a code block that gets JIT compiled earlier than any code block that references those assemblies.
By adding the [MethodImpl(MethodImplOptions.NoInlining)] to methods that reference the dynamically loaded assemblies, it will prevent the optimizer from trying to inline the method code.
So lately I've been working on a project where the application (or executable,whatever you wish to call it) needs to be able to load and unload assemblies not found within the executable's folder at all. (might even be another drive)
For the sake of an example , I want to be able to have my application at D:\AAA\theAppFolder , and the assemblies of the DLL files at C:\BBB\Assemblies
Looking thoroughly , I found out AppDomain allow the ability to unload themselves and any attached assemblies , so I figured I'd give it a shot, however there seems to be an issue after a few hours worth of attempts : AppDomains cannot look anywhere outside the application base.
According to AppDomain's documentary (and my own experience) you cannot set the PrivateBinPath outside of ApplicationBase , and if I set the ApplicationBase outside of the drive the application is at (via AppDomainSetup) , I get System.IO.FileNotFoundException complaining it can't find the application itself.
Because of that I can't even reach the phase where I can use the AssemblyResolve ResolveEventHandler to attempt to get the assembly using MarhsalByRefObject inheriting classes...
Here's a few snippets of code related to what I am currently attempting
internal class RemoteDomain : MarshalByRefObject
{
public override object InitializeLifetimeService() //there's apparently an error for marshalbyref objects where they get removed after a while without this
{
return null;
}
public Assembly GetAssembly(byte[] assembly)
{
try
{
return Assembly.Load(assembly);
}
catch (Exception e)
{
Console.WriteLine(e);
}
return null;
}
public Assembly GetAssembly(string filepath)
{
try
{
return Assembly.LoadFrom(filepath);
}
catch (Exception e)
{
Console.WriteLine(e);
}
return null;
}
}
public static Assembly LoadAssembly(string modName, BinBuffer bb)
{
string assembly = pathDirTemp+"/"+modName+".dll";
File.WriteAllBytes(assembly, bb.ReadBytes(bb.BytesLeft()));
RemoteDomain loader = (RemoteDomain)modsDomain.CreateInstanceAndUnwrap(typeof(RemoteDomain).Assembly.FullName, typeof(RemoteDomain).FullName);
return loader.GetAssembly(assembly);
}
To be as specific as I can : Is there any way to get an unloadable AppDomain to load an assembly that is not within the application's base folder?
Each AppDomain has it's own base directory and is not constrained at all by the main application base dir (unless it is the main AppDomain of the application). So you can achieve what you want using AppDomains.
The reason your approach doesn't work is that you are passing Assembly objects between AppDomains. When you call any of the GetAssembly methods, the assembly will be loaded in the child AppDomain but when the method returns, the main AppDomain will try to load the Assembly as well. Of course, the assembly will not be resolved because it is not in the main AppDomains's base dir, private paths or the GAC.
So in general you should never pass Type or Assembly objects between AppDomains.
A simple way to load assemblies without leaking them to the main AppDomain can be found in this answer.
Of course to make your application work with assemblies loaded in child AppDomains you will have to make MarshalByRefObject derived classes that will be your access point between AppDomains.
Maybe you need to use global variable so if you use global variable to fix the problem you can declare readonly global variable for example:
public static string a = "Moosaie";
Convert it to
public static readonly a = "Moosaie";
Anyway you can not use global dynamic value variable for CLR assembly.
I have an asp.net application. I want to load some assemblies dynamically.
this is my code on application start
protected void Application_Start(Object sender, EventArgs e)
{
LoadPrivateAssemblies();
}
private static void LoadPrivateAssemblies()
{
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomainAssemblyResolve;
Assembly.Load("MyDLL");
}
static Assembly CurrentDomainAssemblyResolve(object sender, ResolveEventArgs args)
{
//loads and returns assembly successfully.
}
this code works fine except when a nested c# code calls a class from my dynamic dll Inside an asp.net page (not code-behind)
sample :
<%if(MyDLL.TestObject.Value){%>white some ting<%}%>
what should I do now ?
I think If I know When a new AppDomain is created, it may solve my problem.
I really think you are barking up the wrong tree here.
Assembly.Load(byte[]) does "persist" the assembly in the app domain - otherwise, what else would it be doing?
To illustrate the fact it does, try this:
Create a solution with one console application, and one class library, named OtherAssembly.
In the class library, OtherAssembly, add a single class:
namespace OtherAssembly
{
public class Class1
{
public string HelloWorld()
{
return "Hello World";
}
}
}
In the console application, use this as your program:
public class Program
{
static void Main(string[] args)
{
try
{
using (var fs = new FileStream("OtherAssembly.dll", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
var buffer = new byte[fs.Length];
// load my assembly into a byte array from disk
fs.Read(buffer, 0, (int) fs.Length);
// load the assembly in the byte array into the current app domain
AppDomain.CurrentDomain.Load(buffer);
}
// get my type from the other assembly that we just loaded
var class1 = Type.GetType("OtherAssembly.Class1, OtherAssembly");
// create an instance of the type
var class1Instance = class1.GetConstructor(Type.EmptyTypes).Invoke(null);
// find and invoke the HelloWorld method.
var hellowWorldMethod = class1.GetMethod("HelloWorld");
Console.WriteLine(hellowWorldMethod.Invoke(class1Instance, null));
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
finally
{
Console.ReadLine();
}
}
}
Don't reference OtherAssembly from your main program assembly, instead, compile the solution and manually drop OtherAssembly.dll in the main program's bin folder.
Run the main program. It outputs "Hello World", which it can only have done if the assembly was loaded and retained in memory. You'll note I've been very careful not to give Visual Studio or C# any hint to load this OtherAssembly. No reference was added, the type is not explicitly referenced in C#.
You need to look again at your problem.
[EDIT: in response to you commenting on the fact this is not an ASP.NET application]
OK - I've moved my main program to an ASP.NET web page and tried accessing the assembly both from code behind and the markup - and it works in both situations. I'm sure you are missing something here - it just doesn't make sense that the behaviour of this method - whose job it is to load an assembly into the current app domain - is different in an ASP.NET scenario.
It seems to me there are at least two things to investigate:
If it really is a new app domain being created on each call, it would only be because of an unhandled exception in your application. The quickest way to diagnose this is to use SysInternals Process Explorer. Fire it up - add .Net -> Total AppDomains to the list of columns and watch the app domain count for your process (IIS worker process or web dev) as you run your app. If this increases on each call, you've got unhandled exceptions tearing down one AppDomain and forcing another to be created.
Are you sure this assembly is really being loaded? When you pass the byte array to Assembly.Load, try also writing it out to disk using FileStream.Write. Open the file in Reflector or some similar tool. Is this the assembly you expected it to be. Is it really being loaded at all, or is it an empty/corrupt array?
I'm not trying to be argumentative, but this really feels like you are looking in the wrong place for the cause of the problem.
I think If I know When a new AppDomain is created, it may solve my problem
You should use AssemblyLoad event. AssemblyResolved occurs when the resolution of assembly is fails
I found that the problem is because Assembly.Load(bytes); does not persist the assembly in appdomain. does any body know how to persist loaded assembly using Assembly.Load(bytes); in appdomain ?
finally I decided to switch to LoadFile method instead of load.
EDIT
Finally I switched from Assemly.Load(byte[]) to Assembly.LoadFile(string).
But it did not correct the problem itself. I have added <%#Assembly name="MyDLL"%> To All of my ASPX files that has markup C# code emebeded.
And This Solved my Problem.
Thanks to your answers. I have voted up answers that helped me, but I can not accept your solutions because no one is not complete enough.
I have a function that I want to be sure is compiled JIT (i.e. right before it's called). Are there attributes or assembly settings that will ensure this? If not, then how can I guarantee that a function is compiled JIT?
Thanks!
EDIT:
I want to do this to prevent my application from crashing due to a missing referenced assembly. If my function is compiled JIT, I can wrap the function call that references the missing assembly in a try...catch block and gracefully handle the situation.
It is my understanding that there could be times when whole classes (or even the whole application) could be Jitted - this would cause an error I couldn't possibly catch.
If I read this correctly, you are worried about errors occurring when a class/method is first compiled. This requires awareness of the boundaries. It is obtainable with an extra layer.
If something is 'wrong with SuspectType (ie a required assembly not loading), the try/catch in the following is of no use because the Jitting of Scenario1() itself will fail.
void Scenario1()
{
try
{
var x = new SuspectType();
...
}
catch (..) { ... }
}
It could be rewritten as
void Scenario1a()
{
try
{
Scenario1b();
}
catch (..) { ... }
}
void Scenario1b()
{
var x = new SuspectType();
...
}
But, per Jon Skeet's comment, I'm not sure if this holds for the CFx.
I may be answering the wrong question, but it looks like you mainly want to be able to intercept assembly load failures (whole classes being JITted defeat the try/catch guards around the calls but that's a side effect of using explicit guards around method calls).
If you want to catch assembly resolution woes, instead of specifying a try/catch around every possible call, you could just listen to the global AssemblyResolve event and respond to the assembly loading failures (we're talking about .Net assemblies here, native dll's load failures would have to be tracked with a different mechanism).
static void Main()
{
AppDomain.CurrentDomain.AssemblyResolve += OnResolveFailure;
//...
}
static Assembly OnResolveFailure(object sender, ResolveEventArgs args)
{
//Do something here...
}
The downside of this is you can't do much, except looking for the assembly somewhere else (or logging the error). Specific and graceful logic when a resolution fails is not provided with this way of catching load failures.
Is this something that your app needs to be able to resolve on it's own, or are you debugging some kind of assembly load problem right now?
If the latter, have a look at the fusion log. This is log that is generated by the subsystem that probes for and loads assemblies at run time.
Here's an article: http://www.hanselman.com/blog/BackToBasicsUsingFusionLogViewerToDebugObscureLoaderErrors.aspx