TAA-Module als Web-Service

Es sollen Web-Services implementiert werden um bestimmte Funktionen einer Anwendung für externe Verwendung zur Verfügung zu stellen. Dieses Dokument untersucht die Funktionsweise eines Web-Service, und wie bestehende SEU/TAA Funktionalitäten hierfür verwendet werden können.

Funktionsweise eines Web-Services

Grundvoraussetzung für eine reibungslose Kommunikation zwischen der Implementierung des Web-Service (Server) und einer externen Komponente (Client) ist die sogenannte WSDL. Diese beschreibt mit XML-Schemas die einzelnen Nachrichten, die an einen Web-Service gesendet (Request), oder von dem Web-Service zurück geliefert (Response) werden können. Jeweils eine Request- und eine Responsenachricht werden zusammen als eine Operation des Web-Service veröffentlicht. Diese Operation wird mit einer URL verknüpft. ASP.NET bildet jeweils eine Operation als Methode an einer Klasse ab. Diese Methode bekommt die Requestnachricht als Eingabeparameter, und die Reponsenachricht als Ausgabeparameter übergeben. Bei ASP.NET ist allerdings nicht die WSDL die Ausgangslage, sondern diese wird aus der Definition der Klasse abgeleitet. Aus der Signatur der Methode leitet ASP.NET die Struktur der Request- und Responsenachrichten ab. Für Fehlersituationen gibt es sog. SOAP Faults. Die Struktur dieser SOAP Faults ist vordefiniert, und ein Client muss darauf vorbereitet sein, dass diese von einem Web Service zurückgeliefert werden. ASP.NET übersetzt aufgeworfene und nicht behandelte .NET-Exceptions als SOAP Faults für den Client.

Vergleich mit TAA Modulen

Die Struktur eines Web Service lässt sich auf ein TAA-Modul abbilden. Ein auslösbares Ereignis eines TAA Moduls kann auf eine Operation eines Web-Services abgebildet werden. Die Parameterobjekte können an Hand deren Rolle als Bestandteil der Request- und/oder Responsenachricht aufgenommen werden. Wenn ein Web Service mit ASP.NET implementiert wird, muss in der Methode ein TAA Modul mit dem entsprechenden Ereignis ausgerufen werden, wobei die Eingangsparameter auf die TAA Parameterobjekt übertragen werden müssen. Nach dem erfolgreichen Aufruf müssen dann die Ausgangsparameter aus dem TAA Parameterobjekte bestückt werden. Obwohl sich ADO.NET-Datatables und Datasets für die Abbildung der Datenstrukturen anbieten würden, könnte dies für Clients, die kein ADO.NET verwenden, zu Problemen führen. In Anhang B sind in dem MSDN Artikel Web Services and DataSets einige der Probleme und Tücken in diesem Zusammenhang beschrieben. Laut einem Artikel in MSDN (Siehe Anhang B) werden die übergebenen Daten nicht nach dem XML Schema geprüft. In dem Artikel wird auch eine Lösung vorgestellt, die es allerdings selbst zu implementieren gilt. Hierbei ist zu berücksichtigen, dass nur die Struktur und Format der übergebenen Daten überprüft werden kann. Der Inhalt der Daten muss von der Anwendung geprüft werden.

TAA Module als Web Service

TAA Module sollen als Web Service veröffentlicht werden können. Hierzu soll ein Werkzeug geschaffen werden, welches die Schnittstelle des Web Services für ein TAA Moduls bearbeiten und generieren lässt. Auslösbare Ereignisse sollen als Methoden an diesem Webservice veröffentlicht werden. Die für das jeweilige Ereignis definierten Parameterobjekte sollen als Argumente an diese Methoden übergeben werden können. Die Zustände sollen als Rückkehrwert der Methoden festgelegt werden können. Der Anwendungsentwickler soll die Möglichkeit bekommen, selber die Schnittstelle der Webservice anzupassen, in z.B. die einzelnen Ereignisse nicht oder unter einem anderen Namen veröffentlicht werden, oder die zu übergebenen und zurück gelieferten Daten angepasst und/oder eingeschränkt werden. Diese Anpassungen sollen mit der Definition der Web Service in der EDB gespeichert, und für eine Generierung heran gezogen werden können.

Implementierung des Web Service

Da die WSDL die Voraussetzung ist, mit dem der Client mit dem Server kommuniziert, soll die WSDL die Ausgangslage für denWeb Service sein. Es ist zwar auch möglich, die WSDL von ASP.NET automatisch generieren zu lassen; die Einflussmöglichkeiten auf der .asmx Seite auf dem automatisch generierten WSDL sind aber sehr begrenzt. Einige MSDN Artikel, die dieses Thema vertiefen, sind in Anhang B mit aufgenommen. Neben dem WSDL soll eine .NET Klasse für die .asmx Seite auf dem Server generiert werden. Dieser generierten Klasse soll die Implementierung des Web Service dienen. Diese abgeleitete Klasse soll nicht die Implementierung des TAA Moduls ersetzen, denn das Modul soll mit den bestehenden Möglichkeiten implementiert werden. In diese Klasse sollen die einzelne Methoden und zu übergebenden Daten des Web Service auf die entsprechende Ereignisse und Parameterobjekte für das TAA Modul übertragen werden, und anschließend soll das TAA Modul aufgerufen werden. Daten, die zurück gereicht werden müssen, sollen nach dem Aufruf des TAA Moduls aus den Parameterobjekten extrahiert werden. Außerdem soll hier der von dem TAA Modul gesetzte Zustand auf einen Rückkehrwert für die Web Methode übertragen werden. Die zu generierende Klasse soll auf einer neu zu implementierende Klasse TeamWiSE.TAA.Web.WebService basieren. Diese Basisklasse stellt die zu bestückenden Parameterobjekte zu Verfügung, und stellt sicher, dass der Aufruf in der richtigen Anwendungsversion ausgeführt wird. In Anhang C ist ein Beispiel aufgenommen, wie die Struktur der generierten WSDL und Klasse aussehen würden.

Datenübergabe

Für die Datenübergabe muss aus der Datenstruktur der Parameterobjekte ein entsprechendes XML Schema generiert werden, das in der WSDL veröffentlicht wird. Für jedes Parameterobjekt soll ein XML Schema erzeugt werden mit den zu transportierenden Feldern. In Anhang A ist eine Tabelle aufgeführt, wie welche Datentypen übertragen werden sollen. Hier sind neben den XML Schema Datentypen auch die entsprechenden .NET Datentypen enthalten. Der Anwendungsentwickler soll in die Lage versetzt werden können, dieses XML Schema anzupassen, indem einzelne Felder ausgeblendet werden, oder, wenn Parameterobjekte in einer Beziehung stehen, diese Beziehung in der Klassenstruktur zu definieren. Bei der Verknüpfung von Parameterobjekten ist zu berücksichtigen, dass keine Zyklen entstehen, da diese nicht in einem XML Schema abgebildet werden können.  In Anhang C ist ein Beispiel aufgenommen, wie 2 Parameterobjekte, die mit einander verknüpft sind, generiert werden.

Fehlerhandling

Das Fehlerhandling soll mit TAA Conditions implementiert werden, indem aufgeworfene TAA Conditions in SOAP Faults übertragen werden. Hierbei soll unterschieden werden können zwischen 2 Arten von SOAP Faults, nämlich Clientseitige und Serverseitige SOAP Faults. Clientseitige SOAP Faults beziehen sich auf den Dateninhalt oder die Art und Weise, wie der Request formuliert wurde. Serverseitige SOAP Faults beziehen sich auf Fehler, die auf dem Server passiert sind. Dies können z.B. technische Fehler sein, wie eine Datenbanksperre. Es soll festgelegt werden können, welche TAA Conditions vom dem TAA Modul geraised werden können, und ob diese auf einen Client oder Server SOAP Fault übertragen werden soll. Eventuell soll ein Default festgelegt werden können, wie TAA Conditions übertragen werden.

Datenmodell

WebService

Enthält allgemeine Eigenschaften des Web-Service wie Name und Beschreibung. Für jedes in der Schnittstelle verwendete Ereignis gibt es eine Instanz der Klasse WebMethod.

WebMethod

Enthält Eigenschaften zu einer Web-Methode wie Name der Methode, auszulösendes Ereignis. Für jeden definierten Parameter gibt es eine Instanz der Klasse WebParameter.

WebParameter

Einhält die Eigenschaften eines Parameters, wie ein Kenzeichen ob In, Out oder In/Out. Diese Klasse basiert auf der Klasse WebElement. Diese enthält Eigenschaften für ein einzelnes Feld aus der XML Datenstruktur wie Name, und mit welchem Feld in einem TAA Parameterobjekt es verknüpft ist. Es enthält ebenfalls einen Verweis auf den WebDatatype

WebDatatype

Beschreibt die Struktur eines WebElements, wobei es 2 Varianten gibt: einen SimpleType wie String, Integer, Datum, etc., oder ein aus mehreren Elementen zusammengestellter ComplexType. Bei letzterem wird unterschieden zwischen GroupBased für redefines und occurs, und ParmBased für verknüpfte Parameterobjekte. ParmBased verweist auf das WebElement, das für die Verknüpfung benötigt wird.

Anhang A: Datentypen

RochadeXML Schema.NET(C#)
character n [variable]
alphanumerisch n [variabel]
alphabetisch n [variable]
<xsd:simpleType>
   <xsd:restriction base=“xsd:string“>
        <xsd:maxLength value=“n“ />
   </xsd:restriction>
</xsd:simpleType>
string
numerisch [+]n.m [gepackt]
<xsd:simpleType>
   <xsd:restriction base=“xsd:decimal“>
        <xsd:totalDigits value=“n“ />
        <xsd:fractionDigits value=“m“ />
   </xsd:restriction>
</xsd:simpleType>
Decimal
numerisch +n (n ⇐ 4)
<xsd:simpleType>
   <xsd:restriction base=“xsd:short“>
        <xsd:totalDigits value=“n“ />
   </xsd:restriction>
</xsd:simpleType>
short
numerisch n (n ⇐ 4)
<xsd:simpleType>
   <xsd:restriction base=“xsd:unsignedShort“>
        <xsd:totalDigits value=“n“ />
   </xsd:restriction>
</xsd:simpleType>
ushort
numerisch +n (n ⇐ 9)
<xsd:simpleType>
   <xsd:restriction base=“xsd:int“>
        <xsd:totalDigits value=“n“ />
   </xsd:restriction>
</xsd:simpleType>
int
numerisch n (n ⇐ 9)
<xsd:simpleType>
   <xsd:restriction base=“xsd:unsignedInt“>
        <xsd:totalDigits value=“n“ />
   </xsd:restriction>
</xsd:simpleType>
uint
numerisch +n (n ⇐ 18)
<xsd:simpleType>
   <xsd:restriction base=“xsd:long“>
        <xsd:totalDigits value=“n“ />
   </xsd:restriction>
</xsd:simpleType>
long
numerisch n (n ⇐ 18)
<xsd:simpleType>
   <xsd:restriction base=“xsd:unsignedLong“>
        <xsd:totalDigits value=“n“ />
   </xsd:restriction>
</xsd:simpleType>
ulong
Timestamp
<xsd:simpleType>
   <xsd:restriction base=“xsd:string“>
        <xsd:pattern
value=“\d{4}\-\d{2}\-\d{2}\-\d{2}\.\d{2}\.\d{2}\.\d{6}/>
   </xsd:restriction>
</xsd:simpleType>
string
DateTime
<xsd:dateTime />
DateTime
Datum
<xsd:date />
DateTime
Uhrzeit
<xsd:time />
DateTime
Binär n
BLOB n
<xsd:simpleType>
   <xsd:restriction base=“xsd:base64Binary“>
        <xsd:maxLength value=“n“ />
   </xsd:restriction>
</xsd:simpleType>
byte[]
Gruppenstufen mit occurs
<xsd:complexType>
   <xsd:sequence>
        <xsd:element name=“name“ maxOccurs=“n“>
            …
        </xsd:element>
   </xsd:sequence>
</xsd:complexType>
Array
Gruppenstufen mit redefines
<xsd:complexType>
   <xsd:choice>
        …
   </xsd:choice>
</xsd:complexType>
object + enum für Type

Anhang B: MSDN Artikel

Die MSDN Artikel sind als PDF Datei in diesem Dokument enthalten. Wenn der Acrobat Reader auf Ihrem Rechner installiert ist, können sie durch eine Doppelklick auf das jeweilige PDF-Symbol die entsprechende Datei öffnen.

Contract-First Service Development

In diesen beiden Artikeln werden die Vor- und Nachteile des .asmx Programmiermodell für Web Services beschrieben, und wieso zuerst die WSDL erfasst werden soll.
contract-first_service_development.pdf techniques_for_contract-first_development.pdf

In diesem Artikel wird (ab Seite 4) beschrieben wie die WSDL von ASP.NET generiert wird, und wie ein selbst erfasstes WSDL verwendet werden kann.
generating_asp.net_web_service_classes.pdf

Web Services and DataSets

In diesem Artikel sind die Nachteile für die Verwendung von ADO.NET DataSets in einem Web Service beschrieben:
web_services_and_datasets.pdf

XML Schema Validation

In diesem Artikel wird eine Lösung beschrieben wie die Struktur der Daten die einem Web Service übergeben werden, geprüft werden können.
xml_schema_validation.pdf

Anhang C: Beispiele

Alle Beispiele basieren auf die Steuerung TS-TARIFRECHNER-ANTRAG. Dieser kennt ein Ereignis BERECHNEN, welches als Web Methode Berechnen für einen Web Service mit den Namen TarifRechner veröffentlicht wird.

Struktur des Web Service

In diesem Beispiel wird die generelle Struktur der Web Service mit Zustandsmapping gezeigt, ohne Datenübergabe und Conditionhandling.

WSDL

Die WSDL für DENWeb Service würde folgendermaßen aussehen:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions targetNamespace="http://www.al.de/Levert/TarifRechner"
   xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
   xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
   xmlns:tns="http://www.al.de/Levert/TarifRechner">
 
   <wsdl:types>
     <xsd:schema elementFormDefault="qualified"
        targetNamespace="http://www.al.de/Levert/TarifRechner">
 
        <xsd:element name="BerechnenRequest">
           <xsd:complexType ... />
        </xsd:element>
        <xsd:element name="BerechnenResponse">
           <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="return" type="tns:TarifRechnerState">
                ...
              </xsd:sequence>
           </xsd:complexType>
        </xsd:element>
        <xsd:simpleType name="TarifRechnerState">
           <xsd:restriction base="xsd:NMTOKEN">
              <xsd:enumeration value="OK" />
              <xsd:enumeration value="ABBRUCH" />
           </xsd:restriction>
        </xsd:element>
     </xsd:schema>
   </wsdl:types>
 
   <wsdl:message name="BerechnenRequestMsg">
     <wsdl:part name="parameters" element="tns:BerechnenRequest" />
   </wsdl:message>
   <wsdl:message name="BerechnenResponseMsg">
     <wsdl:part name="parameters" element="tns:BerechnenResponse" />
   </wsdl:message>
 
   <wsdl:portType name="ITarifRechner">
     <wsdl:operation name="Berechnen">
        <wsdl:input message="tns:BerechnenRequestMsg" />
        <wsdl:output message="tns:BerechnenResponseMsg" />
     </wsdl:operation>
   </wsdl:portType>
 
   <wsdl:binding name="TarifRechnerSoapBinding"
     type="tns:ITarifRechner">
 
     <soap:binding style="document"
        transport="http://schemas.xmlsoap.org/soap/http" />
     <wsdl:operation name="Berechnen">
        <soap:operation
           soapAction="http://www.al.de/Levert/TarifRechner/Berechnen" />
        <wsdl:input>
           <soap:body use="literal" />
        </wsdl:input>
        <wsdl:output>
           <soap:body use="literal" />
        </wsdl:output>
     </wsdl:operation>
   </wsdl:binding>
 
   <wsdl:service name="TarifRechner">
     <wsdl:port name="TarifRechnerSoapPort"
        binding="tns:TarifRechnerSoapBinding">
 
        <soap:address
           location="http://localhost/TarifRechner/TarifRechner.asmx" />
     </wsdl:port>
   </wsdl:service>
 
</wsdl:definitions>

.asmx-Klasse

namespace AL.Levert.TarifRechner
{
      using System;
      using System.Web.Services;
      using System.Web.Services.Description;
      using System.Web.Services.Protocols;
 
      [WebService(Name="TarifRechner")]
      [WebServiceBinding(
            Name="TarifRechnerSoapBinding",
            Namespace="http://www.al.de/Levert/TarifRechner",
            Location="TarifRechner.wsdl")]
      public class TarifRechner : TeamWiSE.TAA.Web.WebService
      {
            public TarifRechner()
            {
                  base("TS-TARIFRECHNER-ANTRAG", "SSTR", "LEVERT", "BL_029");
            }
 
      [WebMethod()]
      [SoapDocumentMethod(
                 "http://www.al.de/Levert/TarifRechner/Berechnen",
                 RequestElementName="BerechnenRequest",
                 ResponseElementName="BerechnenResponse",
                 Use=SoapBindingUse.Literal,
                 ParameterStyle=SoapParameterStyle.Wrapped)]
      public TarifRechnerState Berechnen(...)
            {
                  // Daten übertragen auf TAA Parameterobjekte
 
                  base.Invoke("BERECHNEN");
 
                  // Daten zurück übertragen
 
                  switch (base.State) {
                  case "OK": 
                        return TarifRechnerState.OK;
                  case "ABBRUCH":
                        return TarifRechnerState.ABBRUCH;
                  }
            }
      }
 
      [XmlType(Namespace="http://www.al.de/Levert/TarifRechner")]
      public enum TarifRechnerState
      {
            OK,
            ABBRUCH,
      }
}

Parameterverknüpfung

Für dieses Beispiel wird ein Ausschnitt aus  2 der Parameterobjekte ANTVTG (Antrag) und ANVTGT (Vertragsteil) die für das Ereignis BERECHNEN der Steuerung TS-TARIFRECHNER-ANTRAG definiert sind verwendet.

WSDL

<xsd:complexType name="Antrag">
   <xsd:sequence>
     <xsd:element name="Vertragsnummer">
        <xsd:simpleType>
           <xsd:restriction base="xsd:unsignedLong">
              <xsd:totalDigits value="11" />
           </xsd:restriction>
        </xsd:simpleType>
     </xsd:element>
     <xsd:element name="Vetragsteile">
        <xsd:complexType>
           <xsd:sequence>
              <xsd:element name="Vertragsteil"
                type="tns:Vertragsteil" maxOccurs="unbounded" />
           </xsd:sequence>
        </xsd:complexType>
     </xsd:element>
     ...
   </xsd:sequence>
</xsd:complexType>
<xsd:complexType name="Vertragsteil">
   <xsd:sequence>
     <xsd:element name="Vertragsteilnummer">
        <xsd:simpleType>
           <xsd:restriction base="xsd:unsignedShort">
              <xsd:totalDigits value="4" />
           </xsd:restriction>
        </xsd:simpleType>
     </xsd:element>
     ...
   </xsd:sequence>
</xsd:complexType>
 
<xsd:element name="BerechnenRequest">
   <xsd:complexType>
     <xsd:sequence>
        <xsd:element name="Antrag" type="tns:Antrag" />
        ...
     </xsd:sequence>
   </xsd:complexType>
</xsd:element>

.asmx-Klasse

[XmlType(Namespace="http://www.al.de/Levert/TarifRechner")]
public class Antrag
{
  public System.UInt64 Vertragsnummer;
  [XmlArrayItem(IsNullable=false)]
  public Vertragsteil[] Vetragsteile;
  ...
}
 
[XmlType(Namespace="http://www.al.de/Levert/TarifRechner")]
public class Vertragsteil
{
  public System.UInt16 Vertragsteilnummer;
  ...
}
 
  ...
  public TarifRechnerState Berechnen(Antrag Antrag, ...)
  {
       // Daten übertragen auf TAA Parameterobjekte
     base.Parameter["AntVtg"].objField("VSG-VSG-LNR") = Antrag.VertragsNummer;
     foreach (Vertragsteil o in Antrag.Vertragsteile) {
       base.Parameter["AnVtgT"].objAdd();
       base.Parameter["AnVtgT"].objField("VSG-VSG-LNR") = Antrag.Vertragsnummer;
       base.Parameter["AnVtgT"].objField("LVT-LVT-LNR") = o.Vertragsteilnummer;
       ...
     }
     ...
 
     base.Invoke("BERECHNEN");
     ...
  }
faq:allg:webservice · Zuletzt geändert: 06.06.2017 16:30

Copyright © 1992-2024 TeamWiSE Gesellschaft für Softwaretechnik mbH         Adressen |  Kontakt |  AGB |  Datenschutzerklärung |  Impressum