I currently have a problem where if I set up a new App Domain and use AppDomain.Load, The Assembly gets loaded twice (Once into the new App Domain, and once into the default App Domain)
The code I am using to load the Assembly is as follows:
AppDomain dom = AppDomain.CreateDomain(_dllname);
AssemblyName assemblyName = new AssemblyName();
assemblyName.CodeBase = directory + _dllname;
Assembly a = dom.Load(assemblyName);
When I use this code the Assembly loads correctly into my new AppDomain (with the same name as the dll) but for some reason, always loads into the default AppDomain (in this occasion, IQUS_Main.vshost.exe)
Here is a screenshot of the issue, immediately after the dom.Load line:
Related
This works fine:
Assembly MyAssembly = Assembly.LoadFile(Directory.GetParent(Application.LocalUserAppDataPath) + "\\MyLib.dll");
Type MyAssemblyType = MyAssembly .GetType("MyLib.someType");
object MyAssemblyObject = Activator.CreateInstance(deviceControlType);
This returns file not found exception:
AppDomain MyDomain = AppDomain.CreateDomain("MyDomain");
Assembly MyAssembly = MyDomain.Load(File.ReadAllBytes(Directory.GetParent(Application.LocalUserAppDataPath) + "\\MyLib.dll");
I've implemented an AssemblyResolve event with no luck, I've tried various methods to solve this but it seems loading from file isn't at all the same when using AppDomain. My initial issue is I need to use an appdomain so that I can unload the .dll to change the file, then reload it when the changes ahve been made.
It seems this question has been asked before, but none of the answers around here on StackOverlow actually solve my issue, though some answers say it should.
What I see, is when I call AppDomain.CreateInstanceFromAndUnwrap to load create a type in another AppDomain than the main AppDomain, the assembly that holds that type is also loaded in the main application domain and that is what I do not want.
I have the following code:
AppDomainSetup appDomainSetup = new AppDomainSetup();
appDomainSetup.ApplicationName = #"TestDomain";
appDomainSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory;
AppDomain testDomain = AppDomain.CreateDomain(appDomainSetup.ApplicationName, null, appDomainSetup);
object other = testDomain.CreateInstanceFromAndUnwrap(#"TestLib.dll", #"TestLib.Class1");
When I print the assemblies loaded in the main application domain before I call CreateInstanceFromAndUnwrap, the TestLib.dll is not loaded in the main application domain, while it is loaded in the main application domain right after this call!
Also changing the `CreateInstanceFromAndUnwrap call to:
byte[] assemblyBytes = File.ReadAllBytes(#".\TestLib.dll");
testDomain.Load(assemblyBytes);
will result in the TestLib.dll being loaded in both application domains.
What can I do to prevent the TestLib.dll to be loaded in the main application domain?
i'll start with describing the issue. So I'm dynamically creating a .dll with Roslyn Compiler. Later i need to analyze it to make some security checks with reflection.
If I use following code:
...
var assemblyStream = new MemoryStream();
compilation.Emit(assemblyStream);
var assembly = Assembly.ReflectionOnlyLoad(assemblyStream.ToArray());
It works but I'm unable to unload assembly as this is impossible this way. So i found out I should Create AppDomain, because you can Unload AppDomain with all loaded assemblies. So now my code looks like this:
...
var assemblyStream = new MemoryStream();
compilation.Emit(assemblyStream);
var temporaryAppDomain = AppDomain.CreateDomain("TemporaryAppDomain");
var assembly = temporaryAppDomain.Load(assemblyStream.ToArray());
...
AppDomain.Unload(temporaryAppDomain);
And now following line:
var assembly = temporaryAppDomain.Load(assemblyStream.ToArray());
Throws FileNotFoundException ( Could not load file or assembly ... )
What am I missing ? How can I load my new assembly into temporary AppDomain ?
Currently I'm compiling and loading an assembly at runtime. The assembly contains always the same namespaces and classes. When I'm doing this
multiple times in the same application instance, does always the newest assembly will be used, when creating new instances of the classes which are in the assembly? Or is this not guaranteed?
You're creating exactly what you're trying to create. This may or may not be what you want to create, though.
Most likely, your assemblies don't have a specific name, but rather, a randomized unique name - in that case, the types are entirely different and only accidentally similar as far as .NET is concerned. Types from two different compilations are entirely unrelated, and are not compatible. This may or may not be a problem when you're accessing them through an interface defined outside of the dynamic assembly, depending on how exactly you're using the types.
If you add an assembly name, the situation gets a bit more complicated. You can't load the same assembly twice (the old one is not replaced by the new one), so you need to change the version. However, two versions of the same assembly cannot be loaded in the same application domain (except when doing "fun" with AssemblyResolve etc. - but that's quite tricky to get right). The second assembly would simply fail to load.
In the end, the Type you're trying to instantiate is the one you do instantiate (barring the use of binding redirects, which are bonus fun :P). If some piece of your code holds on to a Type from a previous compilation, that's what it's going to create.
If your question is if I load an assembly in AppDomain
Assembly a1=Assembly.Load(Array of Assembly);
And then change code with roslyn like class name and create new assembly of your project and load it again
Assembly a2 =Assembly.Load(Array of Assembly);
Now is a2 is loaded in CurrentDomain ?
My answer is no .a1 is now in CurrentDomain.
You can test it .
So for work with new assembly you have to use below solution.
You need to load this assembly in another AppDomain and every time you can Unload this AppDomain and create it again and load assembly again
First create a class that CurrentDomain will load instance of that to another AppDomain this object of class must load your assembly and it's dependencies to second AppDomain .
// you can create this class in another project and
// make assembly .because you need a copy of it in
//folder that you set for ApplicationBase of second AppDomain
public class AssemblyLoader : MarshallByRefObject
{
AssemblyLoader()
{
AppDomain.CurrentAppDomain.AssemblyResolve += LoaddependencyOfAssembly;
}
public void LoaddependencyOfAssembly(object sender,)
{
//load depdency of your assembly here
// if you has replaced those dependencies to folder that you set for ApplicationBase of second AppDomain doesn't need do anything here
}
public Assembly asm {get;set;}
public void LoadAssembly(MemoryStream ms)
{
asm= Assembly.Load(ms.ToArray());
}
}
in where you want to load assembly
AppDomainSetup s=new AppDomainSetup(){ApplicationBase="anotherFolderFromYourAppBinFoldr};
AppDomain ad= AppDomain.CreateDomain("name",AppDomain.CurrentDomain.Evidence,s);
Type t = typeof( AssemblyLoader);
AssemblyLoader al = ( AssemblyLoader) ad.CreateInstanceAndUnwrap(t.Assembly.FullName,t.FullName);
// load assembly here by Stream or fileName
al.LoadAssembly(ms );
// now assembly loaded on ad
// you can do your work with this assembly by al
// for example create a method in AssemblyLoader to
// get il of methods with name of them
// Below IL is in CurrentDomain
//when compiler goes to GetIlAsByteArray you are in second AppDomain
byte[] IL = al.GetILAsByteArray("NameOfMethod");
//And unload second AppDomain
AppDomain.Unload(ad);
I am trying to host a text template class proxy inside a new AppDomain.
I have some old scripting code that does something similar, that contains this working code:
_ScriptAppDomain = AppDomain.CreateDomain(scriptDomainFriendlyName);
_ScriptProxy = (IScriptEngineProxy)_ScriptAppDomain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
"LVK.Scripting.ScriptEngineProxy");
However, when I try this with my new class, with the following
_TemplateDomain = AppDomain.CreateDomain(templateDomainFriendlyName);
_TemplateProxy = (ITemplateProxy)_TemplateDomain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName,
"TextTemplate.TemplateProxy");
I just get "FileNotFoundException", with the following details:
Could not load file or assembly 'TextTemplate, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bb70a2e62a722ace' or one of its dependencies. The system cannot find the file specified.
What am I missing?
Basically, I have a Template class in the TextTemplate namespace (and assembly), which tries to load a TemplateProxy class (descending from MarshalByRefObject) into the new appdomain, but it appears my main assembly is not loaded into this domain.
This works if I use the older code, but not with this new one, but I can't spot the difference.
Here's some more details:
Assembly is not registered with the GAC (neither was the old one, which works)
I have not overridden any AssemblyResolve event (neither did the old one, which works)
I'm not averse to handling the AssemblyResolve event, if that is what is needed. I just found it odd that my old code worked, and this didn't.
Assumying your assembly is in the same directory as your current application base, try specifying Application Base:
AppDomain.CreateDomain(templateDomainFriendlyName, null,
new AppDomainSetup
{
ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase
});
If you don't know what you are doing, the best way to create a new domain is to copy all settings from the current one, like this:
var newDomain = AppDomain.CreateDomain("NAME",
AppDomain.CurrentDomain.Evidence,
AppDomain.CurrentDomain.SetupInformation);
I had similar issues, and making a copy resolved them for me