Laden...

Plugin-System - Individuell entladbare plugins?

Erstellt von Maaka vor 14 Jahren Letzter Beitrag vor 14 Jahren 6.097 Views
Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren
Plugin-System - Individuell entladbare plugins?

Hi,

habe etwas mit Plugins rumprobiert.
Mit DLLs laden über Assembly.LoadFrom.
Leider musste ich dann aber feststellen, das man die nicht einfach wieder "entladen" kann.
Da ich aber Plugins brauche die ich jederzeit entladen kann (einzeln) frage ich mich wie?

Ich habe rausgefunden das man anscheinend nur ganze AppDomains entladen kann. Also müsste ich für jedes Plugin eine eigene AppDomain erzeugen? Das würde bestimmt recht viel Resourcen fressen denke ich mal?

Jemand meinte auch SecondLife würde die Assemblies zu einer anderen AppDomain transferieren und dann nur die eine AppDomain entladen, die noch die Assemblies hat, welche entladen werden sollen.
Jedoch habe ich nichts wirklich brauchbares darüber gefunden wie man Assemblies zu einer anderen AppDomain überträgt...

Was ist also das beste für ein Plugin System mit dem man einzelne Plugins entladen kann? (so das man z.b. die DLL/PLugin Datei austauschen und dann neu laden kann, wenn man etwas am Plugin ändern will... aber ohne gleich das ganze Programm neu zu starten)

3.971 Beiträge seit 2006
vor 14 Jahren

Erstell eine seperate AppDomain. Beispiele findest du hier und auch bei MSDN, Codeproject usw.

Hast du allerdings ein Plugin-System was auch UserControls hin- und herschaufelt, kannst du das nur mithilfe von WPF und System.Addin gescheit verwenden. Für alles andere gehts leider nicht mit seperater AppDomain.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

Gelöschter Account
vor 14 Jahren

Jemand meinte auch SecondLife würde die Assemblies zu einer anderen AppDomain transferieren und dann nur die eine AppDomain entladen, die noch die Assemblies hat, welche entladen werden sollen.
Jedoch habe ich nichts wirklich brauchbares darüber gefunden wie man Assemblies zu einer anderen AppDomain überträgt...

was hat secondlife damit zu tun?
jedenfalls kann man keine geladenen assemblies "transferieren". sonst könnte man sie auch entladen....

für dein vorhaben siehe: [FAQ] Eigene Anwendung pluginfähig machen

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

Erstell eine seperate AppDomain. Beispiele findest du hier und auch bei MSDN, Codeproject usw.

Hast du allerdings ein Plugin-System was auch UserControls hin- und herschaufelt, kannst du das nur mithilfe von WPF und System.Addin gescheit verwenden. Für alles andere gehts leider nicht mit seperater AppDomain.

Naja, aber pro Plugin eine eigene AppDomain?

was hat secondlife damit zu tun?
jedenfalls kann man keine geladenen assemblies "transferieren". sonst könnte man sie auch entladen....

für dein vorhaben siehe:
>

@SL: Naja jemand meinte das halt und da SecondLife für Scripte Mono benutzt... vllt. meinte er auch die OpenSim Variante.

Hm.. naja wie man Assemblies läd weiß ich nicht. Das SharpDevelop habe ich jetzt nicht direkt ausprobiert. AddIns habe ich mal etwas rumprobiert aber weder bei SharpDevelop noch bei System.AddIns sehe ich wirklich eine Möglichkeit die geladenen AddIns zu entalden?

Gelöschter Account
vor 14 Jahren

das geht wie bereits mehrfach erwähnt nur mit separaten appdomains. der aufwand hierfür hält sich im übrigen in grenzen.... solange du nciht mehrfach die sekunde versuchst sowas zu machen.

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

das geht wie bereits mehrfach erwähnt nur mit separaten appdomains. der aufwand hierfür hält sich im übrigen in grenzen.... solange du nciht mehrfach die sekunde versuchst sowas zu machen.

Hmm.. okay also muss ich einfach für jedes Plugin eine AppDomain anlegen ^^ danke

N
335 Beiträge seit 2006
vor 14 Jahren

Hallo maaka,

die Forumssuche liefert folgende Startpunkte für weitere Recherchen:
Erweiterungssystem realisieren
[gelöst] Getrennte AppDomain ohne CreateInstance*

Mfg NeuroCoder

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

hmm habe mal etwas herumprobiert...

RemoteLoader.cs:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace WinIRCBot
{
   [Serializable]
   class RemoteLoader
   {
      public RemoteLoader()
      {
      }

      public object LoadFrom( string assemblyFile )
      {
         Assembly pluginAssembly = Assembly.LoadFrom( assemblyFile );
         //Activator.CreateInstance( abc
         return pluginAssembly;
      }
   }
}

Das Interface


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Meebey.SmartIrc4net;

namespace IRCBotPluginInterface
{
   public enum Filters
   {
      Raw = 1,
      Query = 2,
      Notice = 4,
      Message = 8,
   }

   public interface IIRCBotPlugin
   {
      string Name { get; }
      Filters Events { get; }
      void RunPlugin( Filters MessageType, IrcMessageData Data, IrcClient myIRCBot );
      void Test();
   }
}

Das Plugin


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Meebey.SmartIrc4net;
using IRCBotPluginInterface;
using System.Windows.Forms;

namespace TestPlugin
{
   public class TestPlugin : IIRCBotPlugin
   {
      public Filters Events
      {
         get { return Filters.Message; }
      }

      public string Name
      {
         get { return "TestPlugin"; }
      }

      public void RunPlugin( Filters MessageType, IrcMessageData Data, IrcClient myIRCBot )
      {
         if( Data.Message == "!test" )
            myIRCBot.SendMessage( SendType.Message, "#Feitoism", "test1" );
         return;
      }

      public void Test()
      {
         MessageBox.Show( "tesT2233" );
      }
   }
}


Das Laden:


               AppDomain pluginDomain = AppDomain.CreateDomain( "pluginDomain" );
               RemoteLoader remoteLoader = (RemoteLoader)pluginDomain.CreateInstanceAndUnwrap( typeof( RemoteLoader ).Assembly.FullName, typeof( RemoteLoader ).FullName );
               Assembly pluginAssembly = (Assembly)remoteLoader.LoadFrom( dll );
               foreach( Type type in pluginAssembly.GetTypes() )
               {
                  if( type.GetInterface( "IIRCBotPlugin" ) == typeof( IIRCBotPlugin ) )
                  {
                     IIRCBotPlugin plugin = (IIRCBotPlugin)Activator.CreateInstance( pluginDomain, Assembly.GetExecutingAssembly().FullName, type.FullName );
                     plugin.Test();
                  }
               }

nun kriege ich aber bei


IIRCBotPlugin plugin = (IIRCBotPlugin)Activator.CreateInstance( pluginDomain, Assembly.GetExecutingAssembly().FullName, type.FullName );

TypeLoadException

Could not load type 'TestPlugin.TestPlugin' from assembly 'WinIRCBot, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

Habe zuerst pluginAssembly.FullName probiert aber dann sagte es FileNotFoundException... und keine ahnung wie ich das hinkriege :x

32 Beiträge seit 2010
vor 14 Jahren

Also ich würd jetzt sagen, dass du wirklich pluginAssembly.FullName verwenden musst, da in dieser Assembly deine Klasse definiert ist.

Die FileNotFoundException deutet laut MSDA (Activator.CreateInstance-Methode (AppDomain, String, String)) darauf hin, dass die pluginAssembly nicht gefunden wurde. Seltsam.

#define struct union[

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

Hm wie kann sie denn dann geladen werden wenn sie nicht gefunden wird.

3.971 Beiträge seit 2006
vor 14 Jahren

Warum lädt dein RemoteLoader(LoadFrom-Methode) nicht die jeweiligen Plugin(s) aus der übergebene Assembly? Der RemoteLoader ist ja bereits schon in der neuen AppDomain.

Mit der AppDomainSetup-Klasse lassen sich mehr Einstellungen an der neuen AppDomain festlegen, beispielsweise kannst du auch Probing-Pfade, ein neues Basis-Verzeichnis angeben oder eine App.Config angeben

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

Hab auch probiert die es im RemoteLoader zu laden, dann läds zwar aber wenn ich von dem anderen Form das zurückgegebene objekt aufrufe sagt es bei CurrentDomain.FriendlyName, die Haupt-AppDomain, nicht die, die ich erstellt habe

3.971 Beiträge seit 2006
vor 14 Jahren

WinForm funktioniert nicht über AppDomain-Grenzen hinweg. Bei WPF ist die Sache hingegen möglich.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

Maaka Themenstarter:in
21 Beiträge seit 2010
vor 14 Jahren

WinForm funktioniert nicht über AppDomain-Grenzen hinweg. Bei WPF ist die Sache hingegen möglich.

Hmm versteh ich dann nicht? Dann müsste es ja einen Fehler anzeigen oder so etwas

3.971 Beiträge seit 2006
vor 14 Jahren

Jede AppDomain kann eine seperate WinForm-Anwendung enthalten - diese wird auch vom BS wie ein seperater Prozess behandelt. Es ist allerdings nicht möglich eine Klasse abgeleitet von System.Window.Forms.Control über die eine AppDomain-Grenze zu übertragen.

Du kannst allerdings an das jeweilige Plugin, die aktuelle Position des Controls übertragen. Das Control legst du auf ein seperates Form ohne Caption und positionierst es und zeigst es ganz normal über Show an. Allerdings musst du auch berücksichtigen, dass das Control, bzw. das Form auch irgendwann wieder versteckt werden muss, wenn nicht mehr gebraucht.

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...

R
98 Beiträge seit 2005
vor 14 Jahren

Hallo, ich benötige auch das Entladen bzw. Aktualisieren von Assemblies. Bei mir geht es dabei um WPF UserControls (System.Windows.Controls). Kann ich dafür den AppDomain ansatz (pro Assembly eine AppDomain) nicht nutzen?

In meiner aktuellen Umsetzung wird das Assembly geladen und die Instanz des UserControls als Grid Child hinzugefügt.

Es ist allerdings nicht möglich eine Klasse abgeleitet von System.Window.Forms.Control über die eine AppDomain-Grenze zu

Würde dieser Ansatz über CreateInstanceAndUnwrap nicht funktionieren?

Ist es richtig diese Frage diesem Thread anzufügen oder soll ich dafür etwas neues aufmachen?

Vielen Dank und Gruss

3.971 Beiträge seit 2006
vor 14 Jahren

WPF-Controls sind zwischen verschiedenen AppDomains übertragbar. (WinForm hingegen nicht).

Vorraussetzung, du musst System.Addin verwenden. Siehe AppDomain Isolated WPF Add-Ins

Es gibt 3 Arten von Menschen, die die bis 3 zählen können und die, die es nicht können...