Wie eigene Methoden in C# Script definieren und aufrufen

Hallo,

hat hier jemand evtl. ausreichend Erfahrungen gesammelt, um mir sagen zu können, wie ich am geschicktesten eigene Methoden in C# Scripte einbinde, die ich im Visual Studio schreibe?

Ich arbeite momentan an einem größeren Script, das Adressdaten aus dem CRM ausliest, den User nach einem Startpunkt mit maximaler Fahrtdauer fragt, diese Informationen an die Google Distance Matrix weiterleitet, die Antwort-Json-Datei in diverse Klassen deserialisiert und dann abgleicht, welche Ziele innerhalb der maximalen Fahrtzeit liegen und diese anschließend als Filter im CRM anwendet.

Der Ablauf funktioniert an sich. Allerdings nur verlässlich aus dem Visual Studio heraus. Folgendes habe ich so weit gelernt:

  1. Zunächst hatte ich alle Klassen und Methoden in einer eigenen dll, die ich aus dem Script heraus referenziert habe und deren Methoden ich dann aus static void Main() aufgerufen habe. Da in der dll auch mit cRM.COM Objekten gearbeitet wurde, ist das Script beim zweiten Durchlauf abgestürzt mit der NullReferenceException.
    → War leider mein Fehler, dass wurde im SDK Dokument beschrieben.

  2. Das führte zu folgendem Vorgehen: Da ich die Json Datei in eigene Klassen deserialisieren muss, die Combit API aber laut SDK PDF keine eigenen Klassen zulässt, habe ich diese also in der externen dll belassen, die Methoden, die auf Combit Objekte zurückgreifen aber in das Script übertragen.
    Das SDK Handbuch gibt vor, dass die Methoden mit static versehen sein müssen, also war mein Aufbau wie folgt:

public static void Main() {}
public static void Methode1() {}
public static void Methode2() {}
etc.
Dieser Aufbau entspricht im Wesentlichen also dem Aufbau des Beispiel Scripts in der SDK Pdf auf Seite 58.
Der Aufbau hat dazu geführt, dass die Methoden dem CRM, bei Start aus CRM, nicht bekannt waren, da sie, dem C# Script Beispielprojekt/Whitepaper folgend, in #region Visual Studio only fallen.

Jetzt habe ich das Script so umgebaut, dass es sich für mich eher wie ein VBScript anfühlt, als wie ein Programm, das in einer C# Logik geschrieben wurde.

Kann mir jemand auf die Sprünge helfen, ob ich hier irgendwo einen Denkfehler beim Aufbau gemacht habe?

Vielen Dank
David

Hallo David,

nein, ich glaube, Du hast keinen Denkfehler. Ich bin auf dasselbe Problem gestoßen. Die static-Methoden scheinen der einzige Weg zu sein. Die Beschränkung auf die statischen Methoden erscheint mir völlig unverständlich, zumal es ja mit cs-script eine erprobte Engine unter MIT-Lizenz gibt, die ohne diese Einschränkungen auskommt.

Als Workaround könnte man die cs-script-Engine über die .exe-Datei mit dem eigenen Script als Parameter aufrufen, etwa so:

Dim oShell, result Set oShell = CreateObject("WScript.Shell") result = oShell.Run( "csws.exe %PRJDIR%\myscript.csscript", 1, true )

In myscript.csscript hat man dann auch die Möglichkeit, richtige Klassen wie z.B. Forms zu definieren:

//css_reference "C:\Program Files (x86)\combit\cRM\combit.CSharpScript22.Engine.x86.dll";
using System;
using System.Drawing;
using System.Windows.Forms;

namespace Scripting
{
    public class Form1 : System.Windows.Forms.Form
    {
        private System.ComponentModel.Container components = null;
        private System.Windows.Forms.LinkLabel linkLabel1;

        public Form1()
        {
            InitializeComponent();
            
            combit.cRM.COM.cRMApplication cRM = new combit.cRM.COM.cRMApplication(combit.cRM.COM.EApplicationStartType.GetActiveobject);
            this.linkLabel1.Text = cRM.CurrentProject.Name + " ist super";
        }
        
        ...
        
        #region Windows Form Designer generated code
        private void InitializeComponent()
        {
            this.linkLabel1 = new System.Windows.Forms.LinkLabel();
            this.SuspendLayout();
            // 
            // linkLabel1
            // 
            this.linkLabel1.Location = new System.Drawing.Point(179, 93);
            this.linkLabel1.Name = "linkLabel1";
            this.linkLabel1.Size = new System.Drawing.Size(200, 22);
            this.linkLabel1.TabIndex = 0;
            this.linkLabel1.TabStop = true;
            this.linkLabel1.Text = "";
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(405, 204);
            this.Controls.Add(this.linkLabel1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.ResumeLayout(false);
        }
        #endregion
    }
    
    class Script
    {
        const string usage = "Usage: cscscript WinForm ...\nThe primitive example that demonstrates how to create WinForm application.\n";
        [STAThread]
        static public void Main(string[] args)
        {
            if (args.Length == 1 && (args[0] == "?" || args[0] == "/?" || args[0] == "-?" || args[0].ToLower() == "help"))
            {
                Console.WriteLine(usage);
            }
            else
            {
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new Form1());
            }
        }
    }
}

Viele Grüße
Guido

Guten Morgen Zusammen,

folgende Information habe ich von unseren combit Scripting Spezialisten zu dem Thema bekommen, die ich Ihnen natürlich nicht vorenthalten möchte:

Ihre eigenen Klassen können Sie tatsächlich nicht in der C# Script Datei definieren, dafür legen Sie ein eigenes .NET Projekt an und kompilieren dies als DLL. Stellen Sie dann sicher, dass im eigentlichen C# Script dann alle von Ihnen referenzierten DLLs und .NET-Framework Komponenten (z.B. using System.IO) mittels

// <!--#include ref="..."-->und // <!--#include using="..."-->für den cRM referenziert werden.

Hier können Sie einen Beispiel-Rumpf eines solchen C# Scripts sehen (Syntax-Coloring macht vieles noch deutlicher, daher auch als Screenshot inkl. Einfärbungen am Ende des Beitrags):

[code]
// Anmeldung der von Ihnen verwendeten usings für den cRM.
//
//

//
//

#region Visual Studio Only
// Die von Ihnen verwendeten usings wie z.B. System.IO
using System.IO;

namespace Ihr_Namespace
{
class Ihr_KlassenName
{
public static void Main()
{
cRMApplication cRM = new cRMApplication(EApplicationStartType.GetActiveobject);
#endregion Visual Studio Only

                                // Ihr Code
                                MeineKlasse meinObjekt = new MeineKlasse(cRM);
                                meinObjekt.losGehts();

#region Visual Studio only
}
}
}
#endregion Visual Studio only
[/code](Ihre MeineDLL.dll müssten Sie also gemäß ref=„%PRJDIR%\Scripts\MeineDLL.dll“ ins Solutionverzeichnis im Unterordner „Scripts“ kopieren.)

Beachten Sie, dass Quellcode innerhalb der „Visual Studio Only“ Regionen nicht vom cRM ausgeführt wird. Dieser Teil dient nur dazu, dass Sie das Script im Visual Studio Kontext erstellen und dabei den Visual Studio Komfort genießen können. Der „Rumpf“ und Main() dient ja außerdem lediglich als „Einstiegspunkt“ für die Scripting Engine. In Ihren Klassen können Sie sich dann ganz normal in .NET Manier „austoben“! :slight_smile:

Ihr Ansatz über eine VBScript-Kommandozeile eine Scripting-Kommandozeileninterpreter zu starten ist auch interessant (und kreativ! :slight_smile: ), aber hier haben Sie das Problem, dass Ihnen im Script nicht mehr der cRM-Kontext zur Verfügung steht. D.h. alle internen Objekte (WScript, cRM etc.) haben Sie nicht zur Verfügung. Dies ist eine unserer Meinung nach ziemlich gravierende Einschränkung, da diese ja überhaupt erst den Kontext auf z.B. „den aktuellen Datensatz der cRM-Instanz“, in deren Kontext das Script jetzt ausgeführt wird, überhaupt erst ermöglicht. Dies gilt für Ereignisse ganz besonders (WScript.Event Objekt!). Weitere Information zu dem Thema finden Sie auch in der SDK Dokumentation.

Herzliche Grüße vom Bodensee

Björn Eggstein
Geschäftsführer

combit GmbH
Untere Laube 30
78462 Konstanz
Germany

T +49 (0)7531 906010
F +49 (0)7531 906018

Geschäftsführer: Björn Eggstein, Jochen Bartlau, Brita Dannenmann
Handelsregister: Amtsgericht Freiburg HRB 380959
Umsatzsteuer-Identifikationsnummer: DE 142311808

Hinweis: combit macht keine Angaben zu einer bestimmten Eignung obiger Informationen. Irrtümer und Fehler bleiben ausdrücklich vorbehalten und die Angaben erfolgen ohne Gewähr. Die Angaben stellen nur Beschreibungen dar und enthalten keine Garantie der Beschaffenheit der Produkte. Die Informationen können z.T. auch ein Versuch sein, Ihnen bei einer Aufgabenstellung zu helfen, selbst wenn das Produkt eigentlich nicht für diesen speziellen Zweck vorgesehen wurde. Diese eMail sowie alle damit verbundenen Dateien sind vertraulich und nur für Sie bestimmt. Die darin enthaltenen Informationen dürfen nicht an Dritte weitergegeben werden. Vielen Dank für Ihr Verständnis!

Hallo Herr Eggstein,

das ist genau der Punkt, den ich nicht möchte. Ich will das Scripting ja gerade nutzen, um keine DLL kompilieren zu müssen. So wird das combit-Scripting ja nur zum Vehikel, um die eigentliche Logik in DLLs aufzurufen.

Das kann ich nicht nachvollziehen. Die internen Objekte (zumindest cRM habe ich getestet) sind nutzbar. Das in meinem ersten Beitrag vorgestellte Beispiel-Skript funktioniert.

Viele Grüße
Guido Schöpp

Hallo Herr Schopp,

wenn auf dem Arbeitsplatz mehrere cRM Instanzen laufen (Workflow Server, Autopilot, zwei cRM-Anwendungsinstanzen, etc.), dann ist für das externe .NET Programm ( = Ihr Script per Kommandozeileninterpreter, der macht übrigens auch nichts anderes als eine DLL zu kompilieren.) nicht klar, „welche“ cRM-Instanz (=„cRM“-Objekt) gemeint ist. Das kann zu (gelinde gesagt) unvorhergesehenen Resultaten führen.

Das Event (WScript Objekt) seht nicht zur Verfügung.

Björn Eggstein
Geschäftsführer

combit GmbH
Untere Laube 30
78462 Konstanz
Germany

T +49 (0)7531 906010
F +49 (0)7531 906018

Geschäftsführer: Björn Eggstein, Jochen Bartlau, Brita Dannenmann
Handelsregister: Amtsgericht Freiburg HRB 380959
Umsatzsteuer-Identifikationsnummer: DE 142311808

Hinweis: combit macht keine Angaben zu einer bestimmten Eignung obiger Informationen. Irrtümer und Fehler bleiben ausdrücklich vorbehalten und die Angaben erfolgen ohne Gewähr. Die Angaben stellen nur Beschreibungen dar und enthalten keine Garantie der Beschaffenheit der Produkte. Die Informationen können z.T. auch ein Versuch sein, Ihnen bei einer Aufgabenstellung zu helfen, selbst wenn das Produkt eigentlich nicht für diesen speziellen Zweck vorgesehen wurde. Diese eMail sowie alle damit verbundenen Dateien sind vertraulich und nur für Sie bestimmt. Die darin enthaltenen Informationen dürfen nicht an Dritte weitergegeben werden. Vielen Dank für Ihr Verständnis!