Aktualisierter COMWrapper für den ElsterTransferHandler

16. Mai 2018 16:10

Hallo,

anbei findet Ihr eine auf die aktuelle ElsterTransferHandler-DLL (ab NAV2018 CU04, NAV2017 CU17) angepasste ComWrapper-DLL für NAV2009R2. Die Entwicklung basiert auf der von Carsten zur Verfügung gestellten ComWrapper-DLL und wurde bei und für ENERTRAG AG durchgeführt.

Die Installationsmethode ist gleich geblieben, leider aber nicht die Aufrufkonvention. Man muß einige Anpassungen, u.a. in Codeunit 11001 machen.

Was hat sich geändert, das die alte Methode nicht mehr geht? Die Zertifikate und zugehörigen Passworte werden jetzt alle als BLOB in der Datenbank gespeichert. Sie werden beim Übertragungsaufruf als zusätzliche Parameter mit übergeben. Die alte Zertifikatsreferenz wird nicht mehr benutzt. Die neue ElsterTransferHandler-DLL verwendet im Aufruf .net Streams, die man aus NAV2009R2 nicht so einfach durch einen COM-Aufruf aus einem C/SIDE Stream herausbekommt. Also muss man sich etwas einfallen lassen. Unsere Lösung sieht so aus:

1. Zertifikate und Passworte werden über Aufrufe in den ComWrapper geladen. Zertifikate werden aus dem BLOB Einzelzeichenweise gelesen und über Integer in den ComWrapper geschrieben. Das ganze geschieht um genau den gleichen byte-stream zu bekommen den man vorher im BLOB gespeichert hat. Passworte werden in einer Textvariable gespeichert und über String in den ComWrapper geladen. Dies in der Hoffnung das String <> BSTR soweit ausprogrammiert wurde das die Codepage 850 komplett in einen richtigen .net String konvertiert wird, und so am wenigsten Schaden angerichtet wird.

2. Aufruf der eigentlichen Übertragung mit der bisherigen Aufrufsyntax. Der COMWrapper baut dann aus den zuvor geladenen Zertifikatsdaten den entsprechenden .net-Aufruf zusammen.

Das hat zur Folge das man Felder dafür in der Datenbank braucht. Das sind:

4 Felder für die https-Serveradressen, Text[250] (am besten in Table 11013 Electronic VAT Decl. Setup)
1 Feld für das FrontEnd-Zertifikat, BLOB (ebenda, im neuen NAV Standard aber in Table 11014 Certificate zu finden)
1 Feld für das Client-Zertifikat, BLOB (ebenda, im neuen NAV Standard aber in Table 11014 Certificate zu finden)
1 Feld für das Password des Client-Zertifikats, Text[250] (ebenda, im neuen NAV Standard aber in Table 11014 Certificate zu finden)
1 Feld für das Firmenzertifikat, BLOB (Table 11014 Certificate)
1 Feld für das Passwort des Firmenzertifikats, Text[250] (ebenda)

Wir haben noch zusätzlich bei jedem BLOB ein Längenfeld angelegt, hier wird beim Import des BLOBs die Länge abgelegt. Kann man auch anders machen, wenn man sich traut einen InStream doppelt auf das selbe BLOB zu benutzen.

Wie ruft man jetzt in Codeunit 11001 Sales VAT Adv. Notif.-Transmit den ComWrapper auf?

Code:
OnRun-Trigger
...
Window.OPEN(Text1140003);

IF ISCLEAR(ElsterTransferHandlerNavision) THEN
  CREATE(ElsterTransferHandlerNavision);

//ElectronicVATDeclSetup und Certificate sind bereits geholt
//Fülle Zwischenvarieblen bzw. Streams
ElectronicVATDeclSetup.CALCFIELDS("Elster Certificate","Client Certificate");
IF NOT ElectronicVATDeclSetup."Elster Certificate".HASVALUE THEN
  ERROR(ErrorCertFileMissing,ElectronicVATDeclSetup.FIELDCAPTION("Elster Certificate"),ElectronicVATDeclSetup.TABLECAPTION);
IF NOT ElectronicVATDeclSetup."Client Certificate".HASVALUE THEN
  ERROR(ErrorCertFileMissing,ElectronicVATDeclSetup.FIELDCAPTION("Client Certificate"),ElectronicVATDeclSetup.TABLECAPTION);
ElectronicVATDeclSetup."Elster Certificate".CREATEINSTREAM(certStream);
ElectronicVATDeclSetup."Client Certificate".CREATEINSTREAM(ClientCertStream);
ElsterCertSize := ElectronicVATDeclSetup."ElsterCertificate Size";
ClientCertSize := ElectronicVATDeclSetup."Client Certificate Size";
p12Password := ElectronicVATDeclSetup."Client Certificate Password";
Certificate.CALCFIELDS("PFX File");
IF NOT Certificate."PFX File".HASVALUE THEN
  ERROR(ErrorCertFileMissing,Certificate.FIELDCAPTION("PFX File"),Certificate.TABLECAPTION);
Certificate."PFX File".CREATEINSTREAM(inpfxStream);
pfxPassword := Certificate."PFX File Password";

//Übertrage die Zertifikate aus dem Stream in den ComWrapper, Einzelzeichenweise.
ElsterTransferHandlerNavision.AllocCertArray(ElsterCertSize);
WHILE NOT certStream.EOS DO BEGIN
  certStream.READ(BufferChar);
  ElsterTransferHandlerNavision.DripFeedCertArray(BufferChar);
END;
ElsterTransferHandlerNavision.AllocClientCertArray(ClientCertSize);
WHILE NOT ClientCertStream.EOS DO BEGIN
  ClientCertStream.READ(BufferChar);
  ElsterTransferHandlerNavision.DripFeedClientCertArray(BufferChar);
END;
ElsterTransferHandlerNavision.SetClientCertPassWord(p12Password);
ElsterTransferHandlerNavision.AllocPfxCertArray(Certificate."PFX File Size");
WHILE NOT inpfxStream.EOS DO BEGIN
  inpfxStream.READ(BufferChar);
  ElsterTransferHandlerNavision.DripFeedPfxCertArray(BufferChar);
END;
ElsterTransferHandlerNavision.SetPfxCertPassWord(pfxPassword);

ElsterTransferHandlerNavision.SetHttpServer(GetServerURL);

// ab hier wieder Standard

XMLRespDoc := ElsterTransferHandlerNavision.SendXmlDocument(XMLSubDoc);



Zusätzlich wird diese Zeile ersatzlos gestrichen:

Code:
ConfigNode.text := CertificateRef;


Das wars.

Beigefügt sind einmal die compilierte ComWrapper-DLL und die geänderten(!) Sourcen für das eigentliche Ursprungsprojekt. Man muss beachten, dass der neue ElsterTransferHandler .net 4.5.2 ist und das Target im Projekt entsprechend einstellen. Compiliert haben wir mit VS 2015. Verglichen und Inspiration gesucht haben wir in NAV2017 CU 17.

Ergänzend ein paar zusätzliche Links zu dem Thema:

https://blogs.msdn.microsoft.com/german ... 2-mit-pfs/
viewtopic.php?f=64&t=34887#p132573
viewtopic.php?f=74&t=34843#p132319

LG Jens
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Re: Aktualisierter COMWrapper für den ElsterTransferHandler

16. Mai 2018 16:58

Vielen Dank für die Mühe und das Zurverfügungstellen :-)

Re: Aktualisierter COMWrapper für den ElsterTransferHandler

3. Juni 2018 10:59

Hallo,

kleiner Nachtrag: Man kann den COMWrapper auch in NAV2013 verwenden, das funktioniert direkter (oder überhaupt :mrgreen: ) als wenn man versucht die .net 4.5.2 - DLL einzubinden. Wichtiges Detail: In NAV2009 ist die Variable BufferChar vom Typ Char, in NAV2013 muss man den dort neuen Typ Byte nehmen. Wegen Unicode... Char liest mit binärem READ() zwar ein Byte, wandelt das aber irgendwie intern in etwas um was dann im Wrapper nicht mehr in ein Byte passt.
Bei der Gelegenheit habe ich auch ausprobiert ob man zweimal einen InStream auf das selbe BLOB aufmachen kann. Ja, geht.

Hier die wichtigen Aufrufsequenzen für Codeunit 11001 Sales VAT Adv. Notif.-Transmit:

Initialisierung der Automation als RunOnClient (das Property der Variable ist wirkungslos):

Code:
IF ISCLEAR(ElsterTransferHandlerNavision) THEN
  CREATE(ElsterTransferHandlerNavision,FALSE,TRUE);


Variablen an den COMWrapper übertragen und die Übertragungsfunktion aufrufen:

Code:
//Round one: get the certificate file sizes for the allocation functions
Certificate."PFX File".CREATEINSTREAM(inpfxStream);
Certificate."Elster Certificate".CREATEINSTREAM(certStream);
Certificate."Client Certificate".CREATEINSTREAM(ClientCertStream);

WHILE NOT certStream.EOS DO BEGIN
  certStream.READ(BufferChar);
  ElsterCertSize += 1;
END;
WHILE NOT ClientCertStream.EOS DO BEGIN
  ClientCertStream.READ(BufferChar);
  ClientCertSize += 1;
END;
WHILE NOT inpfxStream.EOS DO BEGIN
  inpfxStream.READ(BufferChar);
  PFXCertSize +=1;
END;

//Round two: Transfer the certificates and passwords into the COM wrapper
Certificate."PFX File".CREATEINSTREAM(inpfxStream);
Certificate."Elster Certificate".CREATEINSTREAM(certStream);
Certificate."Client Certificate".CREATEINSTREAM(ClientCertStream);

ElsterTransferHandlerNavision.AllocCertArray(ElsterCertSize);
WHILE NOT certStream.EOS DO BEGIN
  certStream.READ(BufferChar);
  ElsterTransferHandlerNavision.DripFeedCertArray(BufferChar);
END;
ElsterTransferHandlerNavision.AllocClientCertArray(ClientCertSize);
WHILE NOT ClientCertStream.EOS DO BEGIN
  ClientCertStream.READ(BufferChar);
  ElsterTransferHandlerNavision.DripFeedClientCertArray(BufferChar);
END;
ElsterTransferHandlerNavision.SetClientCertPassWord(p12Password);
ElsterTransferHandlerNavision.AllocPfxCertArray(PFXCertSize);
WHILE NOT inpfxStream.EOS DO BEGIN
  inpfxStream.READ(BufferChar);
  ElsterTransferHandlerNavision.DripFeedPfxCertArray(BufferChar);
END;
ElsterTransferHandlerNavision.SetPfxCertPassWord(pfxPassword);

// Finally call the transfer function (.net 4.5.2)
RespText :=
  ElsterTransferHandlerNavision.SendXmlDocumentString(TransferDoc.OuterXml);


LG Jens

Re: Aktualisierter COMWrapper für den ElsterTransferHandler

27. Juni 2018 10:03

Hallo Herr Glathe,

herzlichen Dank für die Anleitung.

Ich bin erst im April in den Kreis der Nav-Entwickler eingetreten, daher entschuldige ich mich schon einmal im Voraus, falls meine Fragen für Erfahrene Entwickler zu banal sind.

Ich konnte auf meinem System die ComWrapper.dll erfolgreich einbinden, jedoch habe ich noch ein paar Fragen zu den Zertifikaten bzw. zur Verschlüsselung.

Laut der Anleitung werden in der Certificate-Tabelle die neuen BLOB-Felder für die Zertifikate und Passwörter angelegt. Soweit ich das nachvollziehen kann, erfolgt dies analog zu den neuen Nav-Versionen. Daher habe ich versucht, die Funktionalität für den Upload der Zertifikate und Passwörter auch analog aus der aktuellen Nav-Version zu übernehmen. Dabei stoße ich jedoch auf Systemfunktionen zur Verschlüsselung der Dateien, die es im Nav2013 nicht gibt (siehe Codeunit 1266 zB. EXPORTENCRYPTIONKEY, ENCRYPTIONENABLED,...).

Bei meiner Recherche im Internet habe ich leider auch nichts zu diesem Thema gefunden.

Da Sie in Ihrer Anleitung diese BLOB-Felder verwenden, hege ich die Hoffnung, dass Sie eine Lösung für das Verschlüsselungsproblem gefunden haben.

Ich wäre Ihnen sehr dankbar, wenn Sie mir in dieser Angelegenheit weiterhelfen können.

Vielen Dank und Grüße
Yasin

Re: Aktualisierter COMWrapper für den ElsterTransferHandler

27. Juni 2018 13:21

Hallo Yasin,

herzlich willkommen :-) Die Passworte werden entschlüsselt an die Elster-Funktion übergeben. Wenn man sie beim hochladen nicht verschlüsselt, ist das Problem gar nicht erst da. Da verschlüsseln in NAV2013 und auch in NAV2009 mit Bordmitteln nicht geht... hab ichs weggelassen, und es geht. Die Passworte habe ich in NAV2013 auch als BLOB gespeichert.

LG Jens

Re: Aktualisierter COMWrapper für den ElsterTransferHandler

29. Juni 2018 09:12

Hallo Jens,

vielen Dank für die schnelle Antwort. :-D

Nun habe ich alles ohne Verschlüsselung implementiert und bin leider auf ein anderes Problem gestoßen.
Beim versenden der Dateien an Elster erhalte ich folgende Fehlermeldung:

Eine Instanz eines Automatisierungsservers kann mit CLSID = {BF164BC2-3622-30E4-AAC6-6641E796BCE3} nicht erstellt werden.

Hierzu habe ich bereits das Internet durchforstet und entdeckt, dass der Fehler auftaucht, weil die dll nicht im System registriert ist.
Die CLSID = {BF164BC2-3622-30E4-AAC6-6641E796BCE3} zeigt dabei auf die ComWrapper.dll.

Dabei hatte ich die dll auf dem Client und dem Server wie in der Anleitung beschrieben mit gacutil.exe und regasm.exe registriert.

Nach ewigem probieren und suchen im Internet habe ich leider keine Lösung gefunden.

Kannst du mir bei dem Problem vielleicht auch weiterhelfen?

LG Yasin

Re: Aktualisierter COMWrapper für den ElsterTransferHandler

29. Juni 2018 10:41

Hallo Yasin,

hier der Auszug aus unserer Installationsroutine:

Code:
attrib -R *.tlb
gacutil.exe /i interop.MSXML6.dll
gacutil.exe /i Microsoft.Dynamics.ElsterTransferHandler.dll
gacutil.exe /i Microsoft.Dynamics.ElsterTransferHandler.ComWrapper.dll
regasm.exe /tlb:Microsoft.Dynamics.ElsterTransferHandler.ComWrapper.tlb Microsoft.Dynamics.ElsterTransferHandler.ComWrapper.dll


Wenn das erfolgreich war, kann man Codeunit 11001 neu compilieren.

LG Jens

<edit> Zugriff auf Code, das richtige hinschreiben :mrgreen: </edit>