So I'm trying to remove an assembly from my
Thread.GetDomain().GetAssemblies()
area.
I've looked at a couple of explanations on the web so far but have just not been able to figure it out.
This is what I've gotten so far
AppDomain tempD = Thread.GetDomain();
tempD.DoCallBack(LoaderCallback);
AppDomain.Unload(tempD);
System.IO.File.Delete(assemblyName);
private static void LoaderCallback()
{
Assembly.ReflectionOnlyLoad("myAssembly");
//byte[] raw = System.IO.File.ReadAllBytes(test);
//Assembly yacsi = Assembly.Load(raw);
//((IScript)yacsi.CreateInstance("Script")).Go();
}
I've played around with this concept so far but I'm struggling to make the connection because Thread.GetDomain(); does not contain the Unload command
Also I wasn't able to try this part ((IScript)yacsi.CreateInstance("Script")).Go() because I don't know what assembly IScript is nor what to place in the "Script" text section
Any ideas will be appreciated
To add on top #RobertHarvey's comment and also take a step back, what you want to do is create a separate AppDomain and load your assembly into it.
After that you can marshal into your domain various types you intend to use.
When you're done with them, you can unload the application domain, thus getting rid of the assembly.
You should note that inter-domain instance marshaling is done through .NET Remoting, so you may want to play with the remoting lease policies which include, among other things, time values for a marshaled object's lifetime. The reason for modifying lease duration is that a marshaled instance expires after a predefined period of time, if it's not called/used at all. So, you may want to avoid re-marshaling instances over and over again and just prolong their lifetime in your domain.
I think this is a good sample showing how you can load an assembly into a new AppDomain and also unload it. Lots of other samples out there.
As long as you know what the process should be, finding code for it is straightforward.
Related
I'm trying to move a Web project from an IIS hosting to a self hosting structure. I'm using Owin and Web API 2.
It appears that this code:
using (WebApp.Start<Startup>(url))
{
bla...
}
creates a AppDomain (with ID == 1).
Edit: This API is a new interface for accessing data for an already existing software ("only" a few millions lines of code), which means that I can't really do what I want. A "user" is actually more of an "account", which means that I technically can have hundreds of clients connected as the same "user".
End of edit
The problem I'm having is the following: when a client logs in, I create an AppDomain to load its static data. As the same account can have several sessions at the same time (or example the same user connected on his smartphone + computer), I have to make a difference between Session and AppDomain.
So, all my Controllers are called within the AppDomain of the user calling the API, all Services too.
BUT, the Web API 2 seems to add a serialization layer after each Controller. And this serialization layer occurs outside the scope of all the AppDomains I have created manually: it is in the AppDomain with ID == 1.
As the serialization sometimes needs access to the staticdata of the user, I end up having quite frequently serialization errors.
I'm looking for a way to either skip the additional serialization induced by Web API 2 or to compel this serialization to occur within a specific AppDomain.
I haven't found any hint for either ideas in the documentation of the .Net packages I'm using nor in the already asked questions.
Any idea (even a workaround) would be greatly appreciated =)
Thanks for any contribution ;)
The problem really came from a static class (thus defined at an AppDomain level) containing A LOT of information, and used in a few getters of properties throughout the code (I know it's a bad practice, but unfortunately I can't change that right now).
The solution I finally come up with is to kind of serialize everything manually in the created AppDomains, thus solving the problem.
I am trying to make a C++/MFC application (so called "Update Application") that can extract AssemblyVersion information from other applications written in C#/.NET 3.5.
So I can update my C# program according to the version information I can get.
I am pretty sure this is possible, but I don't know which way would be the best way.
I would like to know some techniques or keywords that I can search on the web.
A direct explanation would be appreciated, too.
Here's roughly how we do something similar in a native C++ app.
Compile with /clr. You can do this project-wide or just on selected C++ files, but as far as I remember there were complications doing it selectively and so we just did it project-wide. Also #include <vcclr.h> wherever appropriate.
You'll need to learn about app domains. The main thing here is that once you've loaded an assembly into a domain, you can't unload the assembly except by unloading the entire domain. Since you want to load an assembly, query its version, and then let it go, you'll probably want to create a temporary domain and load into this.
In our system we have a managed C++ class called ModelLoader to load object models, query their version info, and discard them - just like what you want to do. This class is the pivotal element in our managed/unmanaged marshaling.
The code in the ModelLoader has to execute in the temporary domain, because we want it to load the target assemblies there and then unload the domain However, the main app is already running in the main domain and so it needs to be able to marshal method calls across to the ModelLoader in the temp domain. So ModelLoader inherits System::MarshalByRefObject, which allows the .NET runtime to do all the marshaling magic.
So the basic steps are something like this:
Load the assembly that contains the code for ModelLoader. In our system this is built into our main unmanaged .EXE and so we just use Reflection::Assembly::GetExecutingAssembly() to get a handle to it. If your equivalent of ModelLoader is in a separate assembly then you'll have to load it somehow. But since you probably won't need to unload this assembly you can load it into the main domain.
Create a temporary domain.
Create an instance of your ModelLoader class (obviously it will have a different name in your system) within the temporary domain.
Marshal a handle to that new instance back to your main domain.
Use the marshaled handle from within your main domain to execute code in the temp domain.
Unload the temporary domain.
So, in code:
AppDomain ^domain = AppDomain::CreateDomain(L"temp domain");
Assembly ^assembly = Assembly::GetExecutingAssembly();
ObjectHandle ^handle = domain->CreateInstanceFrom(
assembly->Location,L"ModeLoader");
Object ^o = handle->Unwrap();
ModelLoader ^loader = dynamic_cast<ModelLoader^>(o);
loader->GetAssemblyVersion(...);
AppDomain::Unload(domain);
To save you some head-scratching, the namespaces involved are:
System::AppDomain
System::Reflection::Assembly
System::Runtime::Remoting::ObjectHandle
System::Object
Within your ModelLoader, you'll want to load the target assembly and query its version info. Compared to all the other stuff, this is straightforward:
void ModelLoader::GetAssemblyVersion(const wchar_t *filename, AssemblyName ^name)
{
Assembly ^assembly = Assembly::Load(gcnew String(filename));
name = assembly->GetName();
}
(I made this function up just now, so it might not be quite right.)
Another thing to watch out for is assembly resolution. This is how the assembly loader resolves assembly names to DLL files. This is quite a large field in its own right, so I won't talk any more about it right now. (And in any case I'm no expert.) To get started, just make sure that all the assemblies you want to load are in your main app directory and I think you'll be more or less OK. Then when you have the basic loading working, you can worry about more sophisticated resolution.
I have a MEF-based application that can be customized with plugins. This application has several imported parts, and I want to remove some of them at runtime (to be able to delete the .dll that contains them) when a user decides to get rid of that plugin.
CompositionBatch would do what I need, but it needs ComposablePart instances as input parameters for RemovePart() method, and I only have plain objects that implement ISomething interface, or ComposablePartDefinition instances in the AggregateCatalog. So the my question is:
How can I find the ComposablePart
instance that represents the imported
object that I want to get rid of?
Or
alternatively: how do I get the list
of ComposablePart objects that belong
to a certain .dll?
I would use something like follows:
var parts = Container.Catalog.Parts
.Where(p => iDontNeed(p))
.Select(p => howDoIConvertComposablePartDefinition2ComposablePart(p));
var batch = new CompositionBatch();
parts.ToList().ForEach(part => batch.RemovePart(part));
Thank you
how do I get the list of ComposablePart objects that belong to a certain .dll?
To remove the parts from a particular assembly, you could just remove that AssemblyCatalog by calling AggregateCatalog.Catalogs.Remove. You'll have to design your parts to allow for Recomposition though.
However, this will not help you to delete the plugin assembly. The assembly will still be loaded and you cannot change or delete a .NET assembly while it is loaded. The only way to unload an assembly without stopping the process is by unloading the AppDomain in which it loaded. But if you introduce a separate AppDomain for the plugins then you'll basically have to communicate with those plugins via remoting, etcetera.
It's probably much simpler, safer and effective to just stop the application, delete the plugin assembly, and restart.
edit: actually, there is a way to delete the plugin dll file without stopping the process or unloading the entire appdomain: you can enable shadow copying for the app-domain to instruct .NET to make a copy before loading the assembly. The copy will remain loaded, but at least you can delete or replace the original file.
Could MAF help you here? I am not an expert but I understand that with MAF the addins remain in their own process and can be unloaded at run time. I'd guess that this would not give the ideal performance as you are communicating cross process but if that is not a major issue it might be worth taking a look at.
I have a web application that dynamically loads assemblies based on database configuration entries to perform certain actions (dynamic plugin style architecture).
The calls to the objects are in a Factory Pattern implementation, and the object is cached (in a static dictionary<> within the Factory) as the calls can be made many thousands of times in a minute.
The calls to this factory are made from both the main web application and a number of webservices, some in different assemblies/projects.
When I need to update one of these DLLs, I have to recycle IIS to get the DLL released.
As this has an impact on another application on the server, I wanted to know if there was a way I could release the DLL without restarting IIS?
There's absolutely no way to unload a loaded assembly other than killing the AppDomain which is basically what you are doing when you restart IIS.
You can try restarting the application pool not the whole IIS server. Maybe that will do the trick for you
If you have an assembly that you need to load and unload you will have to jump through a few hoops.
the types being loaded must derive from MarshalByRefObject
the types being loaded must derive from an interface that will be used to call them
you must build a remoting based 'loader' to isolate the loaded assembly in a new appdomain, which can be unloaded.
see http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm for a good introduction. It is a bit dated and deals with dynamically generated code but given your rep I would assume that you can extract the relevant information.
I'm trying to load assemblies in a separate app domain, but am running into a very strange problem. Here's some code:
public static void LoadAssembly(string assemblyPath)
{
string pathToDll = Assembly.GetCallingAssembly().CodeBase;
AppDomainSetup domainSetup = new AppDomainSetup
{
PrivateBinPath = pathToDll
};
AppDomain newDomain = AppDomain.CreateDomain("AssemblyLoader",null,domainSetup);
AssemblyLoader loader = (AssemblyLoader)newDomain.CreateInstanceFromAndUnwrap(
pathToDll,
typeof(AssemblyLoader).FullName);
}
AssemblyLoader is another class in the same assembly as this one, and it inherits from MarshalByRef, however for some strange reason, I get a cast exception every time I try to run this. I even hardcoded the path to the DLL instead of using GetCallingAssembly().CodeBase yet I keep getting this exception.
I understand it's hard to answer a question like this without actually seeing it and having more information, but maybe someone has run into a similar situation and would know the common "gotchas" and what I should look out for.
EDIT: The reason I don't want to load it directly is because this is just part of the code. The ultimate goal is that this class will have a method that load assemblies, gets their GUID and some other info about them and stores them in a database for a project I'm working on. Therefore, if I load this assembly in a separate app domain, I can load the others there too and then unload the app domain. No point in having all these assemblies loaded for the duration of the app, if I only need that data.
(EDIT: after reading the exception given, changing answer completely)
It appears the problem is the CreateInstanceFromAndUnwrap call, which uses the LoadFrom semantics of 'pathToDll'. Suzanne Cook detailed the possible sticking point on her blog where your original AppDomain tries to call Load("SomeAssembly, [...]") as opposed to LoadFrom("pathToDll") when trying to resolve the type in question.
Her advice was to hook the AssemblyResolve event on the current domain to do the correct LoadFrom in order to get the type. A little bit of targetted googling brings up a possible solution to the problem based on Suzanne's suggestion.
I don't believe the PrivateBinPath configuration is necessary, beyond that you don't need to use the Path to the DLL, but rather the Assembly's fully qualified name for the first parameter; try:
AssemblyLoader loader = (AssemblyLoader)newDomain.CreateInstanceFromAndUnwrap(
typeof(AssemblyLoader).Assembly.FullName,
typeof(AssemblyLoader).FullName);
There's a lot of good information for what you're trying to do here: How to load a .NET assembly for reflection operations and subsequently unload it?
Check out this article.
Using the code in that article I got a cross app-domain object. I abstracted things a bit with generics and have three assemblies. (i.e. 1 defining the interface, 1 defining the plugin implementation, and the main program which tells the generic what to load.) The original articles code is easy to follow.