Zitat: Das ist denke ich so auch gar nicht vorgesehen, dass Addins miteinander Kommunizieren.
Hehe, genau das szenario habe ich aber auch. (Siehe Thema "Plugin Anwendung ohne System.AddIn")
Ich glaube aber, dass es so abwegig nicht ist, das zu tun: Wenn man das Plugin als Komponente eines skalierbaren Systems sieht ist glaub nicht unbedingt realisierbar, dass der Anwendungsrahmen für jede Anwendung eine Interceptor-Strategie bereit stellt. (Das würde den Plugin-Rahmen vielleicht unnötig konkretisieren) Da will man Plugins installieren können, die als Vermittler zwischen anderen Plugins agieren und dazu natürlich mit denen kommunizieren müssen. Nungut, das ist eine andere Diskussion.
Was ich jedenfalls gemacht habe, um das zu realisieren (auch wenn das laut Microsoft böse oder nicht unterstützt ist):
Eine Dependency-Injection zu realisieren:
- Wenn Plugin2 auf Plugin1 zugreifen möchte:
- Neben Plugin1 und Plugin2 ein Projekt "Plugin1Services" zu definieren.
- Dort wo die Plugins geladen werden stellt man ein System.Dictionary(Of System.Type, IServiceBase) Objekt bereit, in das Plugins ihre Services eintragen können, bzw. von der Plugins Services abfragen können. =>Kardinalität: Eine ServiceMap, mehrere Plugins. Die sieht z.b. so aus:
Public Class Class CServices
Private Items As New System.Collections.Generic.Dictionary(Of System.Type, IServiceBase)
Public Sub AddService(Of TService)(ByVal aService As IServiceBase)
Me.Items.Add(GetType(TService), aService)
End Sub
Public Sub GetService(Of TService) As TService
Return DirectCast(Me.Items.Item(GetType(TService)), TService)
End Sub
End Class
- Man kann auch die System.ComponentModel definierten Klassen verwenden, die folgen auch dem Dependency-Injection-Muster - die map muss man aber glaub auch da selber definieren.
- Falls man den System.AddIn verwendet kann man den PluginKontext vermutlich nicht erweitern. Dann kann man die ServiceMap immer noch als singleton definieren.
- In Plugin1Services definiert man ein IPlugin1Service interface, das von IServiceBase erbt
Public Interface IPlugin1Service
Inherits IServiceBase
Sub DoSomething()
End Interface
- Plugin1 implementiert diesen Service und registriert ihn, wenn das Plugin geladen wird. z.b.
Public Class CPlugin1
Inherits CPluginBase
Implements IPlugin1Service
Public Overrides Sub LoadPlugin(ByVal aPluginContext As CPluginContext)
aPluginContext.Services.AddService(Of IPlugin1Service)(Me)
Me.PluginContext = aPluginContext
End Sub
End Class
- Plugin2 fragt den service ab; im einfachsten fall während der Anwendungslaufzeit, wenn er benötigt wird.
Me.PluginContext.Services.GetService(Of IPlugin1Service).DoSomething
- Der schwierigere Fall ist, wenn man für die Registrierung eines Plugins Services anderer Plugins benötigt oder Plugins auf ereignisse anderer Services reagieren möchten. Ich habe mir mit zwei Methoden beholfen: RegisterComponents und RegisterDependencies. Zuerst wird für alle Plugins RegisterComponents ausgeführt, dannach für alle Plugins RegisterDependencies. In RegisterDependencies kann man sich darauf verlassen, dass alle Services vorhanden sind.
- Wer seine Plugins zur laufzeit laden und entladen möchte muss zur registrierung bzw. aktualisierung der service-abhängigkeiten auf ein Ereigniss 'OnLoadPlugin' und 'OnUnloadPlugin' des Plugin-Rahmens hören.
- Das funktioniert soweit wunderprächtig.
- Aufpassen muss man, wenn man auf die Entkopplung über die Service-Interfaces verzichten möchte und zb. Plugin2 direkt Typen von Plugin1 verwenden will. Dann kommt es leicht zu dem Problem doppelt geladener Assemblies und daraus resultierender Type-Cast-Fehler. (Siehe Thema "Plugin Anwendung ohne System.AddIn") Ich vermute ja schwer, dass es dazu auch unter Verwendung von System.AddIn kommt. Zumal die Kommunikation unter AddIns ja nicht vorgesehen ist (also bidddööö)