Laden...

.NET-Integration in Access-ERP-Lösung (Sage?)

Letzter Beitrag vor 15 Jahren 22 Posts 3.828 Views
.NET-Integration in Access-ERP-Lösung (Sage?)

@Rainbird

Ist vielleicht etwas Offtopic aber handelt es sich bei der ERP Lösung zufällig um Sage Office Line 4.0, welche auch auf Access basiert?

Sage

Nein, es handelt sich um ein Individualsystem.

ERP-Software von der Stange konnte mich bis jetzt noch nicht überzeugen. Nichts was ich auf der letzten CeBit gesehen habe, hat mich vom Hocker gerissen. Aus Architektonischer Sicht ist das alles Stand Anfang der 90er Jahre. Alle rühren am alten Brei weiter und schmeißen nur neue Gewürze rein. Semiramis ist da noch das innovativste, konnte sich aber nicht durchsetzen und ging Pleite (Ich vermute mal, dass es an der Web-Oberfläche lag; Eine Web-Oberfläche ist für ein ERP-System höchstes für Gelegenheitsbenutzer als Zusatzfeature sinnvoll).

Das angepriesene Sage Evolution hat nicht wirklich eine fertige .NET-Integration. Das einzige was an der Oberfläche .NET ist, ist das Navigationsmenü auf der linken Seite. Und das ist nicht mal sauber gemacht, da Windows-Nachrichten über diverse Tastaturanschläge (z.B. Tab-Taste) nicht richtig an das Control weitergeleitet werden (Das ist bedingt durch Inkompatibilitäten in der Nachrichtenschleife zwischen Access und Windows Forms). Alle anderen Formulare sind Access-Formulare. Die greifen nach wie vor direkt auf die DB zu. Von einem zentralen Applikationsserver wurde zwar schon auf der letzten CeBit gesprochen, aber fertig ist da noch gar nix. Selbst die nuen .NET-Libraries sind bei Sage Evolution nicht aus einem Guss: Da gibt es Datenobjekte (OR-Mapping) für alle Entitäten, aber die Beleg-Engine (welche die eigentliche Buchungslogik implementiert) verwendet ihre eigenen Klassen. Strukturen für Vorgänge und Vorgangspositionen sind also z.B. doppelt vorhanden. Mit zentraler Geschäftslogik ist da nix. Auch die Implementierung der Datenzugriffsschicht verursacht Stirnrunzeln. Alles ist doppelt programmiert 1 x mit ADO.NET und 1 x mit altem ADO (COM). Das ganze wird durch ein API verborgen, damit es sich gleich anfühlt. Grund für dieses Konstrukt ist vermutlich die Kompatibilität zu Partner-Lösungen älterer Versionen, die natürlich nicht mal kurz alles in .NET neu schreiben können. ADO und ADO.NET sind so grundverschieden, da kommt nichts gutes dabei raus, wenn man sich auf gemeinsamen Nenner davon beschränkt.

Ich würde mich auf jeden Fall nicht trauen, ein System in diesem Zustand als Evolution zu bewerben. Das ist alles einfach noch nicht richtig fertig und zu unausgegohren. Wenn die Sage-Partner alle mitmachen und nicht bis zuletzt auf dem alten Access-Gaul reiten, kann daraus mal ein schönes System werden. Bis dahin hat Sage aber noch jede Menge zu tun. Das System ist nicht komponentenorientiert aufgebaut, sondern besteht hauptsächlich aus Access-dateien und Access-AddIns (im Sinne von Access-Dateien, deren Code man in anderen Access-dateien aufrufen kann; Nicht mit VSTO o.ä. zu verwechseln). Wenn man an den Standard-Masken was ändern muss/will, wird diese Änderung direkt im Access-VBA-Code bzw. im Access-Formulardesigner druchgeführt. Kein .NET Plug-In-System mit Windows.Forms oder CAB oder WPF. Meiner Meinung nach ist man zu viele Kompromisse eingegangen. Ich werde die Entwicklung von Sage auf jeden Fall weiter beobachten.

Eine Modulweise/Komponentenweise Umstellung halte ich für sinnvoller, als das von COM durchzogene Gewirr, was Sage jetzt schon als Evolution verkaufen will. Statt einzelne Schichten zu migieren, ganze Module mit Durchstich durch alle Schichten migrieren. In der Übergangszeit ist natürlich einiges an Infrastruktur doppelt vorhanden. Das muss man tolerieren. Damit auch ältere Komponenten mit neuen Komponenten kommunizieren können, müssen eben Wrapper geschrieben werden (kein neues .NET Geschäftsobjekt darf ComVisible sein!!! Nur Wrapper-Typen in dedizierten Wrapper-Assemblies). Diese kann man entsorgen, wenn alle Module/Komponenten umgestellt sind. Diese Strategie funktioniert aber nur dann, wenn auch die GUI einzelner Module auf .NET umgestellt werden kann (ohne die komplette GUI der Anwendung und aller Partner-AddOns neu zu schreiben). Access macht es dem .NET-Entwickler allerdings sehr schwer. Der naheliegende Ansatz, Windows.Forms Fenster per API-Funktion SetParent dem Access-Hauptfenster als MDI-Childs unterzuschieben, scheitert leider kläglich (Toolbars funktionieren nicht, Fenster oder Teile davon werden plötzlich nicht mehr korrekt gezeichnet, Tastenanschläge laden plötzlich in einem Access-Fenster, statt im eingebetteten .NET-Fenster, usw...). Ich habe aber mittlerweile einer Lösung gefunden, die sehr gut funktioniert. Hehe!

Hi Rainbird,

wow, mit so einer ausführlichen Antwort hatte ich jetzt nicht gerechnet. Ich bin überwältigt, wieviel Hintergrundwissen du zu einem System hast, das du noch nicht einmal einsetzt.

Hintergrund meiner Frage war, dass einer unserer Kunden Office Line 4.0 einsetzt und wir hin und wieder kleinere Anpassungen am System vornehmen. Hierbei haben wir bisher sowohl kleinere Programme um die OL herum (bzw. direkt auf die DB) in .NET als auch Access Addins geschrieben. Wir sind allerdings kein Developer Partner und es handelt sich hierbei auch nicht um sehr tiefgreifende Dinge. Mir war jedoch bisher nicht bewusst, dass man Windows.Forms direkt in Access integrieren kann. Das finde ich sehr interessant!

Von der Evolution Version habe ich bisher auch nicht viel Gutes gehört. Gibt es denn eigentlich auch für die Version 4.0 eine Möglichkeit die API aus .NET anzusteuern?

Vermutlich aber nicht, oder? Ich denke das war hiermit gemeint:

Damit auch ältere Komponenten mit neuen Komponenten kommunizieren können, müssen eben Wrapper geschrieben werden (kein neues .NET Geschäftsobjekt darf ComVisible sein!!! Nur Wrapper-Typen in dedizierten Wrapper-Assemblies).

Gruß

Christoph

Sage Wissen

Hallo bvsn,

wenn man eine Eigenentwicklung einsetzt, sollte man immer wieder über den Tellerrand schauen und prüfen, wo man steht. Wenn ich erwäge auf eine Standardsystem umzustellen, muss ich es vorher ganz genau kennenlernen. Wer sich nur auf die Marketing-Prospekte der Hersteller und die Zusicherungen der Vertriebsmitarbeiter verlässt, wird hinterher oft unzufrieden sein. Aber zum Glück gibt es ja Demo-Versionen.

Natürlich kann man die .NET Libraries von Sage auch von .NET ansprechen, was nur bedingt von Nutzen ist, da die Oberfläche immer noch komplett in Access ist. Sage hält sich bisher bedeckt, was die Marschrichtung für die zukünftige OL-Oberfgläche angeht. Sowohl Windows.Forms, WCF als auch ASP.NET wurde da schon erwähnt. Da insbesondere WCF noch sehr neu - und unausgereift - ist, werden sie die Entscheidung für eine neue GUI-Technologie auch noch eine Weile hinausschieben. Die Endanwender haben jetzt erstmal Ribbons durch Access 2007 bekommen. Sieht toll aus, bringt aber nicht viel, da sich die Child-Formulare noch genauso anfühlen, wie unter Access 2003.

Natürlich kann man die .NET Libraries von Sage auch von .NET ansprechen, was nur bedingt von Nutzen ist, da die Oberfläche immer noch komplett in Access ist.

Ich meinte jetzt allerdings explizit die alte Version - nicht die Evolution. Dass es für die Evolution Version .NET Libraries gibt ist mir klar. Aber es wäre für mich halt interessant, wenn ich beispielsweise Belege aus .NET Libraries heraus ansprechen könnte. Aber dies halt explizit für die Version 4.0. Dies ginge imho doch nur, wenn Sage hier .NET Wrapper für das COM Objekt zur Verfügung stellen würde.

Hi bvsn,

wenn du ein COM Objekt hast kannst du dir selber auch eine COM-Interopt Assembly erstellen.
Das schwierige ist halt bei größeren Objektstrukturen herauszufinden, wie man die Daten abfragt.

lg
LastGentleman

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

Hallo LastGentleman,

ja, aber der Aufwand den Wrapper selber zu erstellen ist für mich einfach zu hoch.

Gruß

Christoph

Zugriff auf COM-Objekte

Du kannst die COM-Verweise doch einfach in Dein Visual Studio Projekt aufnehmen. Visual Studio erstellt dann automatisch Wrapper-Assemblies. Bei Office allgemein wird das ja auch so gemacht. Du kannst mit dem alten COM-Objektmodell von Sage 4.0 unverändert auch in .NET arbeiten. Allerdings nur unter der vorraussetzung, dass es auch wirklich eine COM-DLL gibt und nicht alles mit Access-Klassenmodulen gemacht ist.

Ach was, von dieser Möglichkeit wusste ich nicht. Ich verwende hier auch SharpDevelop. Vermutlich geht es damit nicht. Ich werde das aber an einem VS Platz mal ausprobieren.

Du meinst vermutlich so, ja?

Gewusst wie: Erstellen von COM-Wrappern

Hallo Hagen,

Ich würde mich auf jeden Fall nicht trauen, ein System in diesem Zustand als Evolution zu bewerben. Das ist alles einfach noch nicht richtig fertig und zu unausgegohren.

in Werbung und Marketing waren KHK und Sage immer schon gut 😉

Grüße Bernd

Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3

COM-Interop

Du meinst vermutlich so, ja?


>

Wenn ich Dich richtig verstanden habe, willst Du die COM-DLLs der alten OL 4.0 in Deiner C#-Applikation nutzen. Dafür müssen generell überhauptkeine Wrapper geschrieben werden. COM-Verweis einbinden und einfach verwenden (Marshal.ReleaseComObject zum expliziten freigeben von COM-Objekten aber nicht vergessen).

Anders sieht es aus, wenn Du Deine C#-Assemblies in Access VBA verwenden willst. Dann musst Du COM-Wrapper schreiben. Das muss aber nicht unbedingt sehr aufwändig sein. Ich mache das oft so, dass ich nur die Funktionen in meinem COM-Wrapper-Projekt verfügbar mache, die wirklich unbedingt in Access gebraucht werden. Da die COM-Wrapper eh nur temporär sind (bis alles migriert ist), müssen die auch keine superschöne API abgeben. Wenn man Modulweise auf .NET umstellt, reicht es oft pro .NET Formular eine Aufruffunktion zu schreiben. So viel Aufwand ist es deshalb gar nicht. Ein einmaliger großer Brocken ist die Integrationsschicht zwischen Access- und .NET-Formularen. Schließlich müssen die Instanzen der .NET-Fenster auch von Access aus verwaltet werden können, da sie ja als MDIChilds im Access-Hauptfenster ausgeführt werden. Außerdem müssen die .NET-Formulare mit dem Acces-Hauptfenster kommunizieren können (wenn z.B. von einem .NET-Fenster aus ein Dialog geöffnet werden soll, der noch in Access implementiert ist). DIe .NET-Formulare dürfen allerdings das Access.Application-Objekt nicht direkt kennen (da es ja nach der kompletten Migration nicht mehr da sein wird). Deshalb ist eine Integrationsschicht mit abstrakten Schnittstellen erforderlich. Hat man diese Integrationsschicht aber einmal stehen, ist der weitere Aufwand relativ gering. Wenn man gut gekapselt hat, sollten auch Kollegen, die keine COM-Interop-Spezialisten sind, in der Lage sein, die Integrationsschicht zu benutzen.

Ja, du hast mich richtig verstanden. Ich dachte immer es wäre so, dass man bei einer eingebundenen COM DLL erstmal genau ergründen muss, wie die einzelnen Funktionen heißen, welche Signatur sie haben, welche Rückgabewerte etc um diese dann entsprechend einzubinden

Also z.B. so:


[DllImport("user32.dll", SetLastError = true)]
		static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId);		

Das wäre ja, wenn man sehr viele Funktionen benötigt, schon recht aufwendig. COM Verweis einbinden und einfach verwenden, bedeutet für mich, dass die Funktionen auch vom IDE angezeigt werden.

Ich habe gerade mal versucht eine der OL DLLs einzubinden aber bekomme dabei gleich einen Fehler:

Fehler beim Laden der Code-Completion-Informationen für OLAbfPrint aus C:\Dokumente und Einstellungen\Burgdorf\Desktop\OLAbfPrint.dll:
Error loading assembly:
System.ArgumentOutOfRangeException: Das angegebene Argument liegt außerhalb des gültigen Wertebereichs.

@bvsn: das was du da baust, ist zum einbinden einer C-API. COM Klassen haben die Information schon drinnen. Da du nicht VS verwendest, muss du die Generierung eine Kommandozeilen Tool machen lassen:
Tlibimp.exe

@rainbird:

du beschreibst meine Traumlösung. Verwendest du eine Loader wie ich hier beschrieben habe oder registrierst du jede COM-Assembly und greifst du dann über COM darauf zu?

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

Hallo Rainbird,

Natürlich kann man die .NET Libraries von Sage auch von .NET ansprechen, was nur bedingt von Nutzen ist, da die Oberfläche immer noch komplett in Access ist. Sage hält sich bisher bedeckt, was die Marschrichtung für die zukünftige OL-Oberfgläche angeht. Sowohl Windows.Forms, WCF als auch ASP.NET wurde da schon erwähnt. Da insbesondere WCF noch sehr neu - und unausgereift

sicher dass du hier WCF meinst und nicht vllt. WPF?

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

Vertipper

sicher dass du hier WCF meinst und nicht vllt. WPF?

Natürlich! Sorry, ich meine natürlich WPF.

COM-Intergations-DLL

Verwendest du eine Loader wie ich
>
beschrieben habe oder registrierst du jede COM-Assembly und greifst du dann über COM darauf zu?

In meinem konkreten Fall habe ich eine einzige COM-Wrapper-Assembly, die per RAGASM registriert wird. In diese Assembly werden alle COM-sichtbaren Wrapper-Klassen reingeklatscht. In Access reicht dann die Einbindung EINES Verweises und man hat Zugriff auf sämtliche gewrappte .NET-Komponenten.

Wie bereits gesagt: Das muss nicht schön sein, sondern zweckmäßig und so einfach, dass auch der klassische Access-Entwickler gut damit zurecht kommt.

Danke Rainbird. Werde es auch so machen müssen.
Der Zugriff mache ich halt über Latebinding, direkte Referenzen stören meinen Chef. 😦

Wollte mir so ne DI Lösung bauen, nur die Appdomains ärgern ein bisschen. Und ohne bleibt das Access hängen.

Wenn du weiter COM Klassen hinzufügst, musst du dann das Control neu registrieren?

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

Registrierung

Wenn du weiter COM Klassen hinzufügst, musst du dann das Control neu registrieren?

Was für ein Control? Du meinst mit Sicherheit die COM-Wrapper-Assembly. Ja, die muss neu registriert werden. In meinem konkreten Fall wird das von einem Deployment-Modul, welches auch automatisch die neuesten DLLs von einem File-Server zieht, erledigt.

Ganz wichtig! Alte Version vor dem Ersetzen Deregistrieren! Sonst besteht die Gefahr, dass Rückstände in der Registry verbleiben und zu bizarren Resultaten führen. Auch wenn Du das per CreateObject (Late Binding) ansprichst.

Access unterstützt leider keine SxS (Selbstbeschreibende COM-Komponenten), sonst könnte man auf die lästige Registrierung komplett verzichten.

und da ist mein Problem.
Mein Programmchen ist so ausgelegt, das es auch installierbar ist als Non-Admin.

Drum wäre mein Ansatz mit dieser DOT.NET Factory Methode die mir fertige COM Objekte zurückgibt, die ich nur EINMAL registrieren muss.

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

Registrierung

Egal wie Du es anstellst, wenn sich die Schnittstelle ändert, musst Du COM-Komponenten neu registrieren. Also immer dann, wenn sich etwas ändert.

Was meinst Du mit ".NET Factory die fertige COM-Objekte erstellt"?

Hab eine ein DOT.NET COM Objekt gebaut, das mir die COM Objekte zurückgibt.

"Das Problem kennen ist wichtiger, als die Lösung zu finden, denn die genaue Darstellung des Problems führt automatisch zur richtigen Lösung." Albert Einstein

Registerzwang

Die Assembly mydll.dll muss trotzdem per REGASM.EXE registriert werden, damit Dein Moniker funktioniert. Ein Moniker ist nur eine Art Factory, entbindet aber nicht vom Zwang der COM-Registrierung. Lediglich mit SxS kannst Du mit COM-Komponenten ohne Registrierung arbeiten. Da wird das, was normalerweise beim registrieren in die Registry eingetragen wird, in einer XML-manifest-Datei gespeichert (Ähnlich wie manifest-Dateien für .NET-Assemblies).

Leider ignoeriet Access diese SxS-Manifeste einfach und lädt die Komponente nicht, wenn sie nicht, nach alter Väter Sitte, in der Registry eingetragen ist.