I have a solutions where three projects are running. One of my project is class library that is isolated from other two class. Now what I want to do is to load it into existing appdomain and auto execute its methods on some event occured from other assemblies in same domain.
I have an event inside that, and i want to execute that event
Is it possible? I not getting the way to autoexecute an. While googling I fouund AppDomain.CreateInstance () but not able to fully utilise it.
OR
Way to trap events occuring in APPDOMAIN. Since i have my dll loaded in domain so how can I trap events occuring inside a domain.
It's reasonably straight forward, this should get you going:
http://msdn.microsoft.com/en-us/library/ms173139(VS.80).aspx
Basically you need to create an object that inherits from MarshalByRefObject, then pass an instance of it to the parent Appdomain. You now have an object running in your appdomain that you can manipulate, be it attaching or raising events, calling methods, whatever.
Related
I have two plugins that are running inside a third-party host application. The host application has an event called DocumentOpened that is raised when a document is opened.
Both plugins, Plugin A and Plugin B, are subscribing to this event. However, Plugin A and Plugin B do not know about each other, and they are executed independently.
Plugin A)
Host.DocumentOpened += SomeCodeA()
Plugin B)
Host.DocumentOpened += SomeCodeB()
What I want to achieve is to give control back to Plugin A after Plugin B has finished handling the DocumentOpened event. In other words, I want to call a method in Plugin A after Plugin B has finished executing.
To do this to do this you will probably need some way for Plugin A and B to communicate with each other. Here are some methods, but there is probably others:
EventWaitHandle
One fairly simple way would be with a system wide synchronization event. Both plugins would each create a EventWaitHandle with the same name. Plugin A could then create a thread that waits on the event, and Plugin B would set the event. If Plugin B does not exist then the event would never be raised. This is a system wide event, so would not work if multiple instances of the host is running, unless you do something like including the processor-id to the event name.
IPC/RPC methods
There are various ways for processes to communicate with each other that could be used:
Named pipes
Message buss
web service
Windows communication foundation
This would be a more complicated solution, but would also be more generic. It could for example handle if the host application decides to run plugins in separate processes, or if you want to transfer more data between the plugins.
Shared assembly
You could create an assembly that is used by both of your plugins. This would allow you to create a singleton object that is shared between both plugins. Something like this:
public class PluginCommunication
{
public event EventHandler MyEvent;
public void RaiseEvent() => MyEvent?.Invoke(this, EventArgs.Empty);
public static PluginCommunication PluginBEvent = new PluginCommunication();
}
plugin B would call PluginCommunication.PluginBEvent.RaiseEvent(); and plugin A would attach an event handler like PluginCommunication.PluginBEvent.MyEvent += PluginAEventHandler;
There are potential pitfalls with this method. if you need to change the assembly in any way you face the risk of plugin A using version 1 and plugin B using version 2, and that may end badly if you are not very careful. Threading issues might also occur if you do not do everything on the main thread.
I am developing a plug-in based application and need to be able to post data (strings, arrays) back to my main EXE when something happens. I'm not quite sure how to go about this, I have thought about creating a thread in the main application that would continuously call a method in the DLL asking for data but this seems very inefficient, is there some sort of event listener I could use for this?
Thanks.
As part of the loading mechanism for the plug-in DLLs, you could pass in a class object / function pointer / delegate / event that the DLL can use to inform the main application of any events the plug-in generates.
Instead of polling the DLL, you should consider using a form of Inversion of Control.
This can be as simple as exposing an event in the dll that your exe subscribes to, or passing in an object (or interface) to the DLL which it can use to call methods to notify your executable, etc. There are many options here, and its difficult to know the best without more information about your architecture.
You can use Delegates/Events on your DLL and subscribe with your EXE ?
Let's set some baselines...
EXE runs
EXE loads a DLL containing plugins
EXE instantiates a type (the "plugin")
Plugin starts waiting for an event
EXE waits
External event (on another thread) is noted by the plugin instance
EXE is notified of the event
If this is the case, the simplest thing is to define an event in your plugin type.
public interface IPlugin
{
public event EventHandler SomethingHappened;
public void StartWatchingForSomething();
}
where the code would be something like...
public static void Main()
{
foreach (var plugin in LoadAllPluginTypes()) // IoC container, MEF, something
{
plugin.SomethingHappened += SomethingHappenedEventHandler;
plugin.StartWatchingForSomething();
}
public void SomethingHappenedEventHandler(object sender, EventArgs e)
{
//derp
}
}
Please note, the event handlers are going to be firing on the same thread as the notification comes in on. For example, if your plugin is responding to file system events (via the FileSystemWatcher), the event handlers will be firing on the same thread as the thread that's executing code "defined in the dll".
If your EXE is a winforms or WPF project, you'll have to do an Invoke or Dispatcher.Invoke to get on the UI thread before updating any visual controls.
If it's a managed DLL (C# ,VB ,CLI/C++ with ref classes )
Reference the DLL in the project's references.
Right click on project -> Add reference -> Browse -> Choose the file.
After you do that you should get the API, and use it in a normal C# way.
The namespaces declared in the DLL will be accessible, and all the objects as well.
I have a main application that loads up some plugins. These plugins are loaded and run in separate app domains using a class that inherits from "MarshalByRefObject"; This all works fine.
What I need now is a way to handle when the plugin wants the main app to do something and a way to dynamically handle this in the main application. If the best way is to poll the plugin for a list of commands, then I can do that, although it seems a bit of a kludge.
What are the best ways to send a request from the plugin across the app domain to the main app?
UPDATE
As an update to the question, I am looking to sent data across the app domain that makes the main app do something, like a "File->New" operation or "GetSomeData()" call. In doing this I need to make the Plugin wait for the main app to complete whatever it is doing, but also be able to decide, main app side, whether or not to execute the requested function/event.
I was doing this by passing the plugin an interface. This interface was implemented by a class in the main app that defined some events. The main app could then subscribe to these events and the plugin could make the main app functions fire. The problem is that the interface only referenced the class as it was when I passed the interface. I.e if I created the class with no events subscribed, then passed the interface like this:
CallbackClass myCallbackClass = new CallbackClass();
pluginInterface.HeresMyCallbackClass((ICallbackClass)myCallbackClass);
the plugin would receive the interface, but any changes to the original class did not propagate. So adding:
myCallbackClass.MyMainAppEvent += new MainEventHandler(MyMainAppFunction);
would not change the plugin's version of the event. The plugin could do this:
//code within plugin
ICallbackClass callToMainApp;
public HeresMyCallbackClass(ICallbackClass cbClass)
{
callToMainApp = cbClass;
}
public CallAMainAppFunction()
{
callToMainApp.CallTheSubscribedFunction(); //This is where it all goes wrong
}
...but the event that it tries to call is null. Now, this is not a problem if I make the main app subscribe to the event first, then pass the interface:
CallbackClass myCallbackClass = new CallbackClass();
myCallbackClass.MyMainAppEvent += new MainEventHandler(MyMainAppFunction); //Subscribe first
pluginInterface.HeresMyCallbackClass((ICallbackClass)myCallbackClass);
The plugin could then call CallTheSubscribedFunction() and the event would fire in the main app. I need to be able to subscribe to events like this on demand because some things/events/data in the main app are available at different times.
So, a lot of info I was trying to avoid having to write out, but I guess my question was too general in relation to my issue.
If anyone has suggestions please let me know. Again, my goal is to allow the plugin to trigger an event in the main app, wait for the main app to finish, then continue with it's execution, where the main app may or may not be subscribed to the events.
Update 2
I realize the above info is specialized to my application, but I'm looking for general suggestions as well. So, if using threads is an option, let me know how a general case might work. If another case would work better and I need to do some redesigning to implement it let me know that as well. Just looking for suggestions here. Thanks.
Mike from the looks of it, you're sort of already what what I think is required and that you should use the Observer Pattern between the class in your primary app domain and the secondary app domain.
You probably just need to iron out the some rough edges in the code you've got, in word words follow/implement the observer pattern.
The way it would work is that the class in the primary domain subscribes to "events" that the class that's been loaded in the secondary app domain raises. I'm guessing that you'll need to do this at the time the secondary app domain classes is instantiated. If you're unloading the app domain, then also make sure of "subscriptions" are "disconnected".
Does that make sense?
Make sure that your CallbackClass inherits from MarshalByRefObject. Otherwise, a copy of the callback class will be created on the other side of the appdomain boundary, making cross-appdomain communication impossible.
I am having a lot of trouble with AppDomains. I currently have an AppDomain containing camera controls, and am trying to have events raised from this secondary AppDomain (like a picture being taken) come back to the main program. Everything seems to be set up correctly (events are registered, functions will run across domain boundry) but when I try to invoke, nothing happens. Everything I can find on the subject involves exceptions being raised rather than just nothing happening at all.
I don't know how much better I can explain it than this, so I made a (very simplistic) diagram, and can post any code that is necessary.
http://a.imageshack.us/img832/8205/cameradiagram.png
A breakpoint fires in the OnPictureUpdated.Invoke(pic); portion, inside the secondary AppDomain, but nothing (either inside CameraContainer or in the main application is raised. I am doing a null check when invoking events, I just didn't put that in the diagram.
+1 for the effort in the question.
I believe this may just be because your CameraContainer isn't a MarshalByRefObject. Because it's attaching to the event, the AppDomain containing the CameraManager effectively needs to call back into the primary AppDomain when the event is raised.
I am using .dll reference to my application.
i want to unload the .dll in a button click event.
How to do it ???
You can't unload an individual assembly - you have to unload a whole AppDomain. In other words, you'll need to load your other assembly (and associated code) in a new AppDomain, then when you want to unload it you unload the AppDomain.
Of course, this makes life a lot harder as you have to worry about marshalling calls between AppDomains - but it's all that .NET allows.
As Jon Skeet wrote, you cannot unload a DLL, but you can load the DLL in another AppDomain - and then unload the AppDomain. That is the only way to do it.
There are some things however that you need to be vary of, because you will naturally have to call functions across the AppDomain. This can happen in two different ways.
If you from one AppDomain (let's call it A), get a reference to an object that is instantiated in AppDomain B, then the default behaviour is that the object is serialized across the AppDomain boundary. That means that the object instance that A accesses is not the same instance that B accesses, and modifications made in A will not be reflected in B, unless you provide functionality to send to object back. This requires that the object is marked with Serializable.
You can however avoid the serialization by letting the class inherit from MarshalByRefObject. If the object is constructed in AppDomain B, and called from AppDomain A, the call will cross the AppDomain boundary. It will still be the same physical thread, so you don't have the overhead of a thread switch as you would in cross-process calls, or COM cross-apartment calls.
But if you construct an object in B that is referenced by an object in A, but the object in B is not accessed for 5 minutes, the object will be disposed. This behaviour can be overridden in MarshalByRefObject.InitializeLifetimeService().
See also the answer to Implementing .NET plug-ins without AppDomains. Note the discussion in the comments, where they point out that it very slowly leaks memory.