Kommunikation zwischen Script und Programm



  • Hallo!

    Ich habe arbeite an einem C# Programm, welches dem User erlauben soll bestimmte Aktionen über C# Scripts auszuühren. Wie ich ein Code Snippet kompiliere und ausführe weiß ich, jedoch bin ich mir bei der Kommunikation nicht so ganz sicher. Wie kann ich dem Script erlauben mit dem laufenden Prozess zu interagieren?

    Danke schon mal im Voraus!



  • Remoting! Hört sich in dem Zusammenhang erstmal seltsam an, aber am einfachsten wäre aus dem C# Code den du dynamisch compilierst nen eigenes Assembly zu erstellen und das dann dynamisch nachzuladen. Am besten ist aber ein eigene AppDomain dafür zu verwenden da sonst der Usercode ne Menge Schaden an deinem eigenen Prog machen könnte. Über AppDomaingrenzen hinaus (User und dein Code) ist es wohl am einfachsten Remoting zu verwenden, weil die Aufrufe gemarshaled werden müssen.

    Ne zweite Möglichkeit die mir einfällt wäre den Usercode wie ne Art Plugin zu verwenden. Muss auch in ne eigene Appdomain, kann aber anders verwendet werden. Nur kann man nicht vom User verlangen wirklich ein Plugin zu schreiben das sich an deine Konventionen hält. Da wäre es aus Usersicht ganz geschcikt wenn er nur die Funktionen schreibt und du noch den Code drum herum fürn Plugin rumbaust bevor du den dann verwendest.

    Sind nur nen paar Ideen, vielleicht hilft dir das ja weiter.



  • Vielen Dank für den Tipp mit Remoting! Ein Plugin um jedes Script zu bauen ist mir zuviel Arbeit, da ist Remoting wohl einfacher :D.



  • Naja, bin selber grad an nem Pluginsystem dran für meine Anwendung und so schwer ists echt nicht 😉 Habs mir nochmal überlegt, glaube Remoting musst du doch nicht unbedingt verwenden, es geht ein wenig harmloser indem deine KLasse einfach von MarshalByRef abgeleitet ist die den Usercode enthält, dann kannst du die über AppDomaingrenzen verwenden.

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp05162002.asp?fram

    Der zugegebnermaßen etwas alte Artikel beschreibt das ganz gut, dort wird zwar das im Zusammenhang mit Plugins besprochen, aber ob nun der Code in ner DLL liegt oder dein dynamisch erzeugtes Assembly bloß im Speicher existiert ist ja egal.



  • Hmm, das kleine Problem ist, dass ich nicht nur auf die Userklasse von meinem Programm aus zugreifen können muss, sondern in begrenzter Weise auch in die andere Richtung.
    Es geht hierbei um die neue Version meines Updaters. Der lädt aus dem Internet eine XML Datei herunter, die die neuesten Versionsinfos über eine bestimmte Datei enthalten. Sollte aber mal mehr als nur ein einfacher Download der neuesten Version notwendig sein, habe ich die Scriptingfunktionalität eingebaut. So kann man z.B. überprüfen ob .NET 2.0 schon installiert ist und wenn nicht das Update abbrechen. Bis jetzt habe ich diese Interaktion mit ein paar fest definierten Variablen im Script gelöst, die nach dem Ausführen vom Updater ausgelesen werden um z.B. herauszufinden ob das Update forgeführt werden soll.
    Jetzt möchte ich die Scriptingfunktionalität erweitern, z.B. soll es möglich sein aus dem Script eine Liste der zu updatenden Dateien abzurufen. Dazu brauche ich die Kommunikation in beide Richtungen (Programm <-> Script).



  • Ich würde es vielleicht so machen: Alle Funktionalität im Hauptprogramm auf die zugegriffen werden kann vom Script wird in eine extra Klasse dafür ausgelagert. Die musst du von MarshalByRefObject ableiten( wegen den AppDomains wenn du die verwendest). Nun kannst du doch deiner Userklasse die irgendwie pluginartig geladen wird dieses Objekt von mir aus im Konstruktor übergeben. Nun kannst du von innerhalb der Userklasse auf des Proxyobjekt zugreifen und die eigentliche Funktionalität die ausgeführt wird, liegt im Hauptprogramm.

    Im Prinzip ists ja so. Deine Userklasse ist einfach ein Assembly was später geladen wird. Die dort benötigte Klasse zur Kommunikation musst du wenn du dafür AppDomains verwendest ja von MarshalByrefObject ableiten, genau so ein entsprechendes Objekt brauchst du dann auch in deiner Hauptapplikation. In welche Richtung dann jetzt die Kommunikation geht, von Host zum Plugin oder vom Plugin zum Host ist ja dann egal, sind ja gleichwertige Kommunikationswege.

    Was mir grad noch einfällt. Musst du wirklich Funktionen aus deinem >>laufenden<< Programm benutzen? Einfacher wäre es doch wenn du dir ne Miniklassenbibliothek schreibst die deine Funktionen beinhaltet als Beispiel mal im Namespace "Updater.Util". Dort sind halt alle benötigten Klassen definiert usw. Nun erstellt ein User so ein Script und wenn er vorgefertigte Funktionen benutzen möchte, dann muss er halt den Namespace einbinden. Nun lässt du das Script mit deinem Programm ausführen. Intern fügst du jetzt beim kompilieren des Usercodes deine Miniklassenbibliothek als Referenz hinzu, der Code müsste kompilieren und fertig. 🙂



  • Leider muss ich teilweise Funtionen aus dem laufenden Programm verwenden. Die Sache mit MBR und den AppDomains sieht aber interessant und vor allem einfacher als Remoting aus. Ich muss mir das ganze jetzt mal ordentlich zu Geüte führen.

    Vielen Dank für die Hilfe!


Anmelden zum Antworten