i have a advanced question which is related to remoting dlls in MEMORY. i have wcf service that take Dlls(Starter.DLL entryType) Also there is a Process dll which is referenced to wpf application . i have some steps:
1) wcf takes Dlls (add to stream memory..)
2) Process dll read from wcf
3) Process dll adds dll to currentdomain
foreach (byte[] binary in deCompressBinaries)
{
AppDomain.CurrentDomain.Load(binary);
}
4) wpf accesses Process' CreateApplication method
this._btnStartApp.Click += (s, args) =>
{
Process appMngr = new Process ();
appMngr.CreateApplication();
};
CreateApplication method :
object obj = appLoader.CreateInstance(appLoader.EntryType);
MethodInfo minfo = obj.GetType().GetMethod("Execute", BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance);
but i can not see Execute method in getMethos result, if QuickWatching,How to run Execute method in another currentdomain ? this Dlls are adding Process Dll's currewntdomain not wpf currentdomain.
AppDomains are tricky to work with then dynamicly loading DLLs.
First; if you cannot see the method then verify you can get the type of the object. If you can see the type the object should be laoded into the current domain. Then you can itterate over the methods and inspect those to see if something is missmatched with the GetMethod call, wich could make it fail to show up. The CreateInstance flag might be the issue, I beleive that one is used for constructors.
Second; If you want things to run in a seperate appdomain (very important when you want to unload the dll later) then you have to build 3 things.
create a set of classes that can handle all the loading and execution of the of the dynamic DLL.
create an interface that allows your main code to talk to this set of classes; this iterface cannot return any types that came from the dynamic DLL; if it does you either laod that DLL or you crash. I recall marshal by ref may be needed, but uncertain, it has been a while.
Attach event handlers to your main Appdomain that notify you when you load a DLL into that appdomain. This will be how you can debug if you are inadvertidly loading the DLL into your current AppDomain.
http://msdn.microsoft.com/library/system.appdomain.assemblyload.aspx
Now you can create a new Appdomain, call your loading code in there and get results trough the interface. If you can complete the call and you had no load events trigered you got it working. you can dispaose of the AppDomain when you are done and the loaded DLL goes along with it.
Good luck, this was tricky to figure out and get working correctly.
Related
I'm trying to create a plugin system. For now, I have a system which can load and unload some dynamic libraries on runtime.
I create a AppDomain this way:
AppDomain is a private member variable.
RemoteLoader is a private member variable.
AppDomainSetup setup = new AppDomainSetup
{
ApplicationName = assemblyName,
ApplicationBase = AppDomain.CurrentDomain.BaseDirectory,
ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
};
AppDomain = AppDomain.CreateDomain(domainName, null, setup);
remoteLoader = (RemoteLoader)AppDomain.CreateInstanceAndUnwrap(assemblyName, typeName);
RemoteLoader keep the list of available Assemblies, can create objects and find objects.
The AppDomain is correctly created. And when I unload, I can see the AppDomain disappearing from module list on Visual Studio.
I'm running Jetbrains dotMemory to find memory leak.
My test for now is:
Load the service, without any plugin
Snapshot
Load some plugin
Let the plugin work for a while
Unload the plugin (unloading the entire AppDomain)
Snapshot
When I compare the two snapshots I can see some objects that never disappear.
Some strings with following texts:
"STEP_Service.Contract.ModuleBase, STEP_Service.Contract, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
"/6ceffbca_d8b4_43be_91ac_39b8cb09ef37/s5bbue3ddey9xxfuevnmvmv9_158.rem"
"c6360995_32bd_46d9_b83b_3fbac3c58c6a/w1ntjmpe4s+1zp1rkmrio_dy_141.rem"
I can't figure out what is happening. The Key Retention Paths show me that:
[
The Stack Trace:
Some RuntimeMethodInfo are leaking:
Other objects like:
No exceptions is thrown by unload function or any place.
My Dispose method call the Unload that is defined like this:
/// <summary>
/// Unloads the plugins
/// </summary>
public void Unload()
{
if (AppDomain == null)
throw new NullReferenceException(nameof(AppDomain));
AppDomain.Unload(AppDomain);
remoteLoader.Dispose();
AppDomain = null;
remoteLoader = null;
}
I know I didn't provide so much code but I really don't know exactly what code I need to give.
If something is missing please ask for.
Every class is derived from MarshalByRefObject and just for test I marked a lot of fields as NonSerializable.
On my concept when I call static method Unload of AppDomain class, everything inside the AppDomain must be released.
EDIT
After a couple minutes executing my service I can see the objects:
Seems like the CrossAppDomainData and other objects (holded by it self) is growing. The object is placed at Generation 2 of GC.
EDIT
After one hour, I can see 2794 NewObjects of type CrossAppDomainData and a couple other objects holded by it
CrossAppDomainData
CrossAppDomainSink
Int64
EDIT
After couple hours, I can see around 32k objects of CrossAppDomainSink, CrossAppDomainData and Int64. The memory of my service grown up from 8k to 17k
EDIT
I discovered the problem but I don't know why this is happening.
To discover the issue, I recreated my service step by step.
Everthing works fine when I load/unload appdomains a lot of times. Everything is released properly and the memory is ok.
But in the next step which is load that dll on another application to have the power of unload, update and load again, something is leaking.
On other words, my actual scenario is:
Service which loads a Core DLL on another AppDomain
The Core DLL can load plugins on runtime
The Core DLL can be changed on runtime
FileSystemWatcher can monitor the folder for changes on CoreDLL. When this happen, the service unloads the CoreDLL after all work is done, loads the new one and start the work again.
The loaded dll (CoreDLL) do the hard work of loading the plugins, watch the plugin folder, and other things. The service only exists to carrie the CoreDLL to have the power of update himself.
So... why the objects mentioned before are leaking? The calls are made by the CoreDLL and not by the service.
How to update dll-file without program being restart?
I want to create my "Updater" class. It's main idea is to
check local(connected to executive file) and server dll-files,
and when newer version is available, copying server file to local.
Code:
Updater updater = new Updater(LOCAL_PATH, SERVER_PATH);
if (updater.IsAvailableNewerVersion)
updater.Update();
Updater's ctor take two paths - to server dll and to local dll and calculate their Versions.
Then I call a property IsAvailableNewerVersion - if it's true (available version is newer then a local), I call Update method.
Main Idea of Update method is to copying server dll-file to local with overwrite, and say to user to restart program.
Code:
public class Updater
{
private readonly string _localPath;
private readonly string _serverPath;
private readonly Version _currentVersion;
private readonly Version _availableVersion;
public Updater(string localPath, string serverPath)
{
_localPath = localPath;
_serverPath = serverPath;
_currentVersion = AssemblyName.GetAssemblyName(_localPath).Version;
_availableVersion = AssemblyName.GetAssemblyName(_serverPath).Version;
}
public bool IsAvailableNewerVersion => _availableVersion.Major > _currentVersion.Major ||
_availableVersion.MajorRevision > _currentVersion.MajorRevision ||
_availableVersion.Minor > _currentVersion.Minor ||
_availableVersion.MinorRevision > _currentVersion.MinorRevision ||
_availableVersion.Build > _currentVersion.Build ||
_availableVersion.Revision > _currentVersion.Revision;
public void Update()
{
try
{
File.Copy(_serverPath, _localPath, true);
}
catch (Exception e)
{
MessageBox.Show("Unable to copying file - " + e);
return;
}
MessageBox.Show("File was successfully updated. Please restart program.");
}
}
Is there a way to check dll-files before they being used?
How to update dll-file without program being restart?
P.S.
I think to use server dll-files, but my program becomes dependent on the server that is not good.
You can't really unload / change the assemblies in a running app-domain; so basically you have two options here:
use a launcher exe that does this work and invokes an inner exe to do the real work, shutting it down when complete (launching a new one either before or after the shutdown)
use multiple app-domains in a single exe, isolating where each loads from
The second approach is more useful for server applications, since you can handle the network IO in the outer exe and funnel requests through to the inner app-domain, just changing a single reference to swap between the two systems. However, app-domains aren't in .NET Core, so you should be aware that it limits your flexibility.
1. Is there a way to check dll-files before they being used?
If you are using a single EXE, it depends on how you use the DLLs. If they are hard coupled to your app, I do not know any way on how to do so.
But if the DLLs are just implemeting interfaces of your core DLLs, you could load them using:
Assembly assembly = Assembly.LoadFrom("path\orbital.dll"));
Type type = assembly.GetType("FullClassName");
object instanceOfMyType = Activator.CreateInstance(type);
This requires you to follow some design patterns, what would be good for your app. But if you already have several DLLs strongly coupled (that means, you added them as reference in your Visual Studio project and are creating objects as var object = new YourOtherDLLNamespace.YorObjectInTheOtherDLL()) then you will probably take a lot of time to change to this approach.
The good about this approach is that you could check the DLL version before loading it, copy a new version from a server (or any other method you find appropriate) and then load it.
2. How to update dll-file without program being restart?
Ok, lets suppose you made just like my suggestion on item 1. Once you loaded the DLL, you wont be able to Unload it. You could destroy all the objects using the garbage collector, but that won't change the way windows is loading it.
So the basic answer for a single EXE is no.
Other solutions
You could wrap your solution in other EXE that keeps constantly checking if the DLL is updated, send a custom event (so that your app EXE would now what is going on an take appropriate action before shutting it down), notify the user and, if the user wants to do so, then you could close the app. Then your other app wrapper would update it and launch the EXE again.
I'm building an extensible service application for my work, and the way it 'extends' is by loading DLL's and executing methods within. It is designed this way so that I do not need to recompile and re-deploy every time we have a new job for it to do. Currently, the service loads a DLL using Assembly.LoadFrom() and then it registers the assembly with the service. In the registration, a Func<object, bool> is passed that dictates the entry point for the new job.
My question is would it be better if I created the instance every time I needed to run the task via something similar to this:
IRunable run = (IRunable)asm.CreateInstance(t.FullName, true);
run.Run();
or would it be better to do it the way I am currently, where I store the Func<> in a class that is called based of a timer?
Timer!
If the performance might stuck because of it (i always had this problem in c#) u can still change it, but a timer gives you more controll over the programm itself...
But implementing a buffer should also just work fine
We are taking a hit the first time some heavy UI screens are loaded. Our project is divided into one main executable and several DLL files. The DLL files can also contain UI screens which are slow the first time they are loaded.
Is there a way (in code) we can preload all the referenced assemblies so as to avoid the JIT compilation hit?
I know there is a tool called NGen. Is it possible to operate NGen in a development environment so we can see its effects instantly? Ideally though, we would like to preload the referenced assemblies from code.
Using C# .NET 3.5 along with DevExpress for our UI components.
I personally found that putting the pre-jitter in 'Program' helped in a certain application, but that is a situation-specific question.
More importantly, the code in wal's answer will crash when it encounters an abstract method, so two lines of code have been added to skip abstract methods.
static Program()
{
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly |
BindingFlags.NonPublic |
BindingFlags.Public | BindingFlags.Instance |
BindingFlags.Static))
{
if ((method.Attributes & MethodAttributes.Abstract) == MethodAttributes.Abstract|| method.ContainsGenericParameters)
{
continue;
}
System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle);
}
}
Console.WriteLine("jitted!");
}
Did you try/look at this?
That is, do the following for each assembly you want to pre JIT.
static void PreJIT()
{
foreach (var type in Assembly.GetExecutingAssembly().GetTypes())
{
foreach (var method in type.GetMethods(BindingFlags.DeclaredOnly |
BindingFlags.NonPublic |
BindingFlags.Public | BindingFlags.Instance |
BindingFlags.Static))
{
System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(method.MethodHandle);
}
}
}
Take a look at NGen. Another option is to use ILMerge to merge all your assemblies into one. Whenever I use ILMerge, I add a post build command to so it happens automatically. The other alternative (untested) is, if you don't mind a longer start-up time, you could manually call Assembly.Load() at the beginning for each assembly.
You can just create instances of the classes located in externall assemblies. Just call the constructor in a limited scope (I mean declare the variable inside a function. It should not be global var because it will delay GC to dispose that instance). This will load the assembly, compile it and cache it. You can even do this in a background thread so the main thread will keep responsiveness.
You can use NGen on any machine - there is no notion of "development enviroment" in CLR... When you use it make sure that NGen'ed images are actually used (see Native Image Generator (Ngen.exe) for instructions and look for FusLogVw note in the document).
You can also pre-JIT through invoking all the code you expect to run (as Davita suggested), but you'll need to invoke each and every method of all classes which in not exactly practical.
You should profile your application to see where time is actually spent - it could be reading of the assemblies from the disk, not JITing itself... You can roughly see it by starting the application, looking at the forms, closing the application and repeating steps. If the second run is much faster then the application spends most of the time reading from the disk, not JITing.
Is there a way to release an object that was accessed using late-binding (i.e. created by the Activator.CreateInstance() method)?
I have an application that transforms files from one format to another. The assemblies that perform these translations live in a folder in my application directory.
When the application first starts up, I can delete these assemblies from the translation folder without any errors. However, once I process a document through the application (and have bound to one of the translation assemblies using late-binding), I can no longer delete the translation assemblies. At this point, I'm receiving an error message stating that the file is "in use by another application".
Is there a way to "release" the late-bound object in my application once I'm finished using it?
Once an assembly is loaded into an application domain it'll remain until the app domain shuts down.
To get around this load the assembly into it's own application domain, for example:
AppDomain app = AppDomain.CreateDomain("PlugInDomain");
ObjectHandle objectHandle = app.CreateInstanceFrom(assemblyPath,
"MyNamespace.MyComponent");
MyComponent component = (MyComponent) objectHandle.Unwrap();
// do stuff
// Now kill app domain, assembly can be overwritten after this.
AppDomain.Unload(app);
Once an assembly is loaded into the executing AppDomain, it cannot be unloaded (regardless of whether it is creating via reflection with Activator.CreateInstance).
The recommended approach here is to implement a secondary AppDomain with a lifetime that can unload when it wants to dispose the assemblies.
There are tons of examples, but here is one:
http://www.dotnet247.com/247reference/msgs/28/142174.aspx.
Since managing the lifetime of secondary AppDomains can be a pain, as an alternative, if you are using ASP .NET and are looking to load many dynamic assemblies, you can check when your current AppDomain becomes saturated with dynamically loaded assemblies by binding to the AppDomain.CurrentDomain.AssemblyLoaded event and keeping count, then requesting the hosting environment recycle the current AppDomain when it hits a critical number (say 500) like:
HostingEnvironment.InitiateShutdown();