Bodo's Dynamics NAV Blog

Bodo ist ein Dynamics NAV Urgestein. Er programmiert NAV seit DOS Zeiten und hat auch keine Scheu vor .NET. Viele Neueinsteiger wurden von ihm in den letzten Jahren zu NAV Entwicklern ausgebildet.

In diesem Blog veröffentlichen Bodo und andere Superhelden Interessantes aus der Welt von Dynamics NAV.

NAV 2009 Web Services und das Geheimnis der Extension Codeunits

Verfasst von Bodo am Freitag, 4. März 2011

Tags: webservices, extension, codeunit, nav, 2009, nav

Wenn Sie einen Web Service auf Basis einer Page veröffentlichen, bekommen Sie einen Standardsatz an Methoden zum Lesen und Schreiben des „SourceTable“ der Page.

Wenn Sie diesen Standardsatz um eigene Methoden ergänzen wollen, müssen Sie eine so genannte Extension Codeunit implementieren. Dabei gelten die folgenden Regeln:

  • Eine Extension Codeunit muss unter dem gleichen Servicenamen wie der Page-basierende Web Service in der Liste der Web Services eingetragen werden.
  • Das Attribut „Veröffentlicht“ muss für die Extension Codeunit nicht gesetzt sein.
  • Nur Funktionen deren erster Parameter vom Typ des „SourceTable“ des Page-Objektes ist, werden als Web Service Methoden veröffentlicht.

 Das folgende Beispiel soll die Verwendung veranschaulichen. Wir veröffentlichen einen Web Service zum Lesen unserer gebuchten Rechnungen. Damit es übersichtlich bleibt, nur mit einer minimalen Anzahl von Feldern.

1. Los geht es mit der Page für den Sales Invoice Header. Beachten Sie bitte, dass ich bei den Namen die Sonderzeichen (Punkte und Leerzeichen) entfernt habe. Das ist nicht zwingend notwendig, da Sonderzeichen automatisch durch Unterstriche ersetzt werden. Mir gefallen nur die Unterstriche nicht.

OBJECT Page 50500 Sales Invoice Service
{
  OBJECT-PROPERTIES
  {
    Date=05.03.11;
    Time=12:00:00;
    Modified=Yes;
    Version List=;
  }
  PROPERTIES
  {
    Editable=No;
    SourceTable=Table112;
    PageType=List;
  }
  CONTROLS
  {
    { 1000000000;0;Container;
                ContainerType=ContentArea }
 
    { 1000000001;1;Group  ;
                Name=Group;
                GroupType=Repeater }
 
    { 1000000002;2;Field  ;
                Name=No;
                SourceExpr="No." }
 
    { 1000000003;2;Field  ;
                Name=SellToName;
                SourceExpr="Sell-to Customer Name" }
 
  }
  CODE
  {
 
    BEGIN
    END.
  }
}

2. Als nächstes brauchen wir einen XmlPort, um die Sales Invoice Lines liefern zu können. Beachten Sie bitte, dass die Angabe des „DefaultNamespace“ zwingend notwendig ist.

OBJECT XMLport 50500 Sales Invoice Lines
{
  OBJECT-PROPERTIES
  {
    Date=05.03.11;
    Time=12:00:00;
    Modified=Yes;
    Version List=;
  }
  PROPERTIES
  {
    Format/Evaluate=XML Format/Evaluate;
    DefaultNamespace=urn:microsoft-dynamics-nav/xmlports/SalesInvoiceLines;
    UseDefaultNamespace=Yes;
  }
  ELEMENTS
  {
    { [{230B615F-189A-450A-88CD-444BFF23CD57}];  ;SalesInvoiceLines   ;Element ;Text    ;
                                                  VariableName=SalesInvoiceLines }
 
    { [{C89F38A1-E7AF-475F-AE8F-8C6E1C96E0AE}];1 ;SalesInvoiceLine    ;Element ;Table   ;
                                                  VariableName=SalesInvoiceLine;
                                                  SourceTable=Table113 }
 
    { [{D36EF3F5-FA9F-42B0-BD9B-CACB89CC9899}];2 ;DocumentNo          ;Element ;Field   ;
                                                  DataType=Code;
                                                  SourceField=SalesInvoiceLine::Document No. }
 
    { [{8859EBB5-7732-4F35-B6B3-AA53C464EEB5}];2 ;LineNo              ;Element ;Field   ;
                                                  DataType=Integer;
                                                  SourceField=SalesInvoiceLine::Line No. }
  }
  EVENTS
  {
  }
  REQUESTPAGE
  {
    PROPERTIES
    {
    }
    CONTROLS
    {
    }
  }
  CODE
  {
    BEGIN
    END.
  }
}

3. Und nun können wir die Extension Codeunit bauen. Da bei der Veröffentlichung der Funktion „GetLines()“ als Web Service Methode der erste Parameter zum „Key“ wird, habe ich ihn auch so benannt. Auch wenn das für eine Variable vom Typ „Record“ ungewöhnlich klingen mag. Weitere „Record“-Variablen als Parameter sind nicht zulässig. Daher verwenden wir einen XmlPort, um die Rechnungszeilen zu liefern.

OBJECT Codeunit 50500 Sales Invoice Service
{
  OBJECT-PROPERTIES
  {
    Date=05.03.11;
    Time=12:00:00;
    Modified=Yes;
    Version List=;
  }
  PROPERTIES
  {
   >
          END;
  }
  CODE
  {
 
    PROCEDURE GetLines@1000000000(Key@1000000000 : Record 112;VAR SalesInvoiceLines@1000000001 : XMLport 50500);
    VAR
      SalesInvoiceLine@1000000002 : Record 113;
    BEGIN
      SalesInvoiceLine.SETRANGE("Document No.", Key."No.");
      SalesInvoiceLines.SETTABLEVIEW(SalesInvoiceLine);
    END;
 
    BEGIN
    END.
  }
}

4. Wir schreiten zur Veröffentlichung.

5. Kontrollieren die Veröffentlichung im Visual Studio 2008.

6. Und schreiben uns ein kleines VisualBasic.NET Programm zum Testen. Die Rechnung „103007“ sollte es in jeder CRONUS AG geben.

Module Application
 
    Sub Main()
 
        Dim ws As SalesInvoiceServiceNAV.SalesInvoice_Service = Nothing
 
        Try
            ws = New SalesInvoiceServiceNAV.SalesInvoice_Service
            ws.UseDefaultCredentials = True
            ws.Url = "http://spiderman:7047/DynamicsNAV/WS/CRONUS AG/Page/SalesInvoice"
 
            Dim invoice As SalesInvoiceServiceNAV.SalesInvoice
            invoice = ws.Read("103007")
 
            If Not invoice Is Nothing Then
 
                Console.WriteLine("Rechnung " & invoice.No & " an " & invoice.SellToName)
 
                Dim lines As New SalesInvoiceServiceNAV.SalesInvoiceLines
                ws.GetLines(invoice.Key, lines)
 
                For i As Integer = 0 To lines.SalesInvoiceLine.Length - 1
                    Dim line As SalesInvoiceServiceNAV.SalesInvoiceLine
                    line = lines.SalesInvoiceLine(i)
                    Console.WriteLine("Rechnung " & line.DocumentNo & " Zeile " & line.LineNo)
                Next
 
            End If
 
        Catch ex As Exception
            Throw
        Finally
            If Not ws Is Nothing Then
                ws.Dispose()
            End If
        End Try
 
        Console.ReadKey()
 
    End Sub
 
End Module

7. Ich habe fertig.