Vergleichen von ASP.NET-Webdiensten mit WCF im Hinblick auf die Entwicklung

Windows Communication Foundation (WCF) verfügt über eine ASP.NET Kompatibilitätsmodusoption, damit WCF-Anwendungen wie ASP.NET Webdienste programmiert und konfiguriert werden können und ihr Verhalten nachahmen können. In den folgenden Abschnitten werden ASP.NET Webdienste und WCF basierend darauf verglichen, was zum Entwickeln von Anwendungen mit beiden Technologien erforderlich ist.

Datendarstellung

Die Entwicklung eines Webdiensts mit ASP.NET beginnt in der Regel mit der Definition komplexer Datentypen, die der Dienst verwenden soll. ASP.NET verwendet XmlSerializer zur Übersetzung von Daten, die durch .NET-Framework-Typen dargestellt werden, in XML zur Übertragung an oder von einem Dienst sowie zur Umwandlung von als XML empfangenen Daten in .NET-Framework-Objekte. Die Definition der komplexen Datentypen, die ein ASP.NET-Dienst verwenden soll, erfordert die Definition von .NET Framework-Klassen, die XmlSerializer in und aus XML serialisieren kann. Solche Klassen können manuell geschrieben oder aus Definitionen der Typen im XML-Schema mit dem Befehlszeilen-XML-Schema/Unterstützungsdienstprogramm für Datentypen, xsd.exe, generiert werden.

Im Folgenden finden Sie eine Liste der wichtigsten Punkte, die Sie beim Definieren von .NET Framework-Klassen kennen müssen, die XmlSerializer zu und von XML serialisieren kann.

  • Nur die öffentlichen Felder und Eigenschaften von .NET Framework-Objekten werden in XML übersetzt.

  • Instanzen von Auflistungsklassen können nur dann in XML serialisiert werden, wenn die Klassen entweder die IEnumerable- oder die ICollection-Schnittstelle implementieren.

  • Klassen, die die IDictionary Schnittstelle implementieren, wie z. B. Hashtable, können nicht in XML serialisiert werden.

  • Die großen Attributtypen im System.Xml.Serialization Namespace können einer .NET Framework-Klasse und ihren Membern hinzugefügt werden, um zu steuern, wie Instanzen der Klasse in XML dargestellt werden.

Die WCF-Anwendungsentwicklung beginnt in der Regel auch mit der Definition komplexer Typen. WCF kann verwendet werden, um dieselben .NET Framework-Typen wie ASP.NET Webdienste zu verwenden.

Die WCFDataContractAttribute und DataMemberAttribute können .NET Framework-Typen hinzugefügt werden, um anzugeben, dass Instanzen des Typs in XML serialisiert werden sollen, und um festzulegen, welche bestimmten Felder oder Eigenschaften des Typs serialisiert werden sollen, wie im folgenden Beispielcode veranschaulicht.

//Example One:
[DataContract]
public class LineItem
{
    [DataMember]
    public string ItemNumber;
    [DataMember]
    public decimal Quantity;
    [DataMember]
    public decimal UnitPrice;
}

//Example Two:
public class LineItem
{
    [DataMember]
    private string itemNumber;
    [DataMember]
    private decimal quantity;
    [DataMember]
    private decimal unitPrice;

    public string ItemNumber
    {
      get
      {
          return this.itemNumber;
      }

      set
      {
          this.itemNumber = value;
      }
    }

    public decimal Quantity
    {
        get
        {
            return this.quantity;
        }

        set
        {
            this.quantity = value;
        }
    }

    public decimal UnitPrice
    {
      get
      {
          return this.unitPrice;
      }

      set
      {
          this.unitPrice = value;
      }
    }
}

//Example Three:
public class LineItem
{
     private string itemNumber;
     private decimal quantity;
     private decimal unitPrice;

     [DataMember]
     public string ItemNumber
     {
       get
       {
          return this.itemNumber;
       }

       set
       {
           this.itemNumber = value;
       }
     }

     [DataMember]
     public decimal Quantity
     {
          get
          {
              return this.quantity;
          }

          set
          {
             this.quantity = value;
          }
     }

     [DataMember]
     public decimal UnitPrice
     {
          get
          {
              return this.unitPrice;
          }

          set
          {
              this.unitPrice = value;
          }
     }
}

Dies DataContractAttribute bedeutet, dass null oder mehr felder oder Eigenschaften eines Typs serialisiert werden sollen, während das DataMemberAttribute bedeutet, dass ein bestimmtes Feld oder eine bestimmte Eigenschaft serialisiert werden soll. Dies DataContractAttribute kann auf eine Klasse oder Struktur angewendet werden. Dies DataMemberAttribute kann auf ein Feld oder eine Eigenschaft angewendet werden, und die Felder und Eigenschaften, auf die das Attribut angewendet wird, können öffentlich oder privat sein. Instanzen von Typen, auf die DataContractAttribute angewendet wurde, werden in WCF als Datenverträge bezeichnet. Sie werden mithilfe von DataContractSerializerXML serialisiert.

Es folgt eine Liste der wichtigen Unterschiede zwischen der Verwendung von DataContractSerializer und der Verwendung von XmlSerializer sowie den verschiedenen Attributen des System.Xml.Serialization Namespaces.

  • Die XmlSerializer Attribute des System.Xml.Serialization Namespaces sind so konzipiert, dass Sie .NET Framework-Typen jedem gültigen Typ zuordnen können, der im XML-Schema definiert ist. Sie bieten daher eine sehr genaue Kontrolle darüber, wie ein Typ in XML dargestellt wird. Der DataContractSerializer, DataContractAttribute und DataMemberAttribute bieten sehr wenig Kontrolle darüber, wie ein Typ in XML dargestellt wird. Sie können nur die Namespaces und Namen angeben, die zum Darstellen des Typs und der zugehörigen Felder oder Eigenschaften im XML-Code verwendet werden, und die Reihenfolge, in der die Felder und Eigenschaften im XML-Code angezeigt werden:

    [DataContract(
    Namespace="urn:Contoso:2006:January:29",
    Name="LineItem")]
    public class LineItem
    {
          [DataMember(Name="ItemNumber",IsRequired=true,Order=0)]
          public string itemNumber;
          [DataMember(Name="Quantity",IsRequired=false,Order = 1)]
          public decimal quantity;
          [DataMember(Name="Price",IsRequired=false,Order = 2)]
          public decimal unitPrice;
    }
    

    Alle anderen Aspekte der Struktur des XML-Codes, der zum Darstellen des .NET-Typs verwendet wird, werden bestimmt durch den DataContractSerializer.

  • Da es wenig Kontrolle darüber gibt, wie ein Typ in XML repräsentiert wird, wird der Serialisierungsprozess für den DataContractSerializer dadurch vorhersehbar und leichter optimierbar. Ein praktischer Vorteil des Designs des DataContractSerializer ist eine etwa zehn Prozent bessere Leistung.

  • Die Attribute in Verbindung mit dem XmlSerializer geben nicht an, welche Felder oder Eigenschaften des Typs in XML serialisiert werden, während das DataMemberAttribute, das mit dem DataContractSerializer verwendet wird, explizit zeigt, welche Felder und Eigenschaften serialisiert werden. Datenverträge sind daher explizite Verträge über die Struktur der Daten, die eine Anwendung senden und empfangen soll.

  • Das XmlSerializer kann nur die öffentlichen Mitglieder eines .NET-Objekts in XML übersetzen, während das DataContractSerializer die Mitglieder von Objekten unabhängig von den Zugriffsmodifizierern dieser Mitglieder in XML übersetzen kann.

  • Aufgrund der Möglichkeit, die nicht öffentlichen Mitglieder von Typen in XML zu serialisieren, hat DataContractSerializer weniger Einschränkungen bei der Vielzahl von .NET-Typen, die in XML serialisiert werden können. Insbesondere kann es in XML-Typen wie Hashtable übersetzt werden, die die IDictionary Schnittstelle implementieren. DataContractSerializer ist mit einer weitaus höheren Wahrscheinlichkeit in der Lage, die Instanzen eines beliebigen zuvor vorhandenen .NET-Typs in XML zu serialisieren, ohne entweder die Definition des Typs ändern oder einen Wrapper dafür entwickeln zu müssen.

  • Eine weitere Folge davon, dass DataContractSerializer auf die nicht öffentlichen Mitglieder eines Typs zugreifen kann, besteht darin, dass sie volles Vertrauen erfordert, während XmlSerializer dies nicht erfordert. Die Berechtigung "Voll vertrauenswürdiger Codezugriff" gewährt vollständigen Zugriff auf alle Ressourcen auf einem Computer, auf die mithilfe der Anmeldeinformationen zugegriffen werden kann, unter denen der Code ausgeführt wird. Diese Option sollte sorgfältig verwendet werden, da voll vertrauenswürdiger Code auf alle Ressourcen auf Ihrem Computer zugreift.

  • Dies DataContractSerializer umfasst einige Unterstützung für die Versionsverwaltung:

    • Die DataMemberAttribute hat eine IsRequired-Eigenschaft, der der Wert "false" für Mitglieder zugewiesen werden kann, die neuen Versionen eines Datenvertrags hinzugefügt wurden und in früheren Versionen nicht vorhanden waren. Dadurch können Anwendungen mit der neueren Version des Vertrags frühere Versionen verarbeiten.

    • Wenn mit einem Datenvertrag die IExtensibleDataObject-Schnittstelle implementiert wird, kann DataContractSerializer das Übergeben von Membern gestattet werden, die in neueren Versionen eines Datenvertrags durch Anwendungen mit älteren Versionen des Vertrags definiert sind.

Trotz aller Unterschiede ist das XML, in das XmlSerializer standardmäßig einen Typ serialisiert, semantisch identisch mit dem XML, in das DataContractSerializer einen Typ serialisiert, vorausgesetzt, der Namespace für das XML ist explizit definiert. Die folgende Klasse, die Attribute zur Verwendung mit beiden Serialisierern hat, wird von XmlSerializer und DataContractAttribute in semantisch identische XML übersetzt.

[Serializable]
[XmlRoot(Namespace="urn:Contoso:2006:January:29")]
[DataContract(Namespace="urn:Contoso:2006:January:29")]
public class LineItem
{
     [DataMember]
     public string ItemNumber;
     [DataMember]
     public decimal Quantity;
     [DataMember]
     public decimal UnitPrice;
}

Das Windows Software Development Kit (SDK) enthält ein Befehlszeilentool namens ServiceModel Metadata Utility Tool (Svcutil.exe). Wie das xsd.exe Tool, das mit ASP.NET Webdiensten verwendet wird, kann Svcutil.exe Definitionen von .NET-Datentypen aus dem XML-Schema generieren. Bei den Typen handelt es sich um Datenverträge, wenn der DataContractSerializer XML im Format des XML-Schemas ausgeben kann. Andernfalls sollen sie für die Serialisierung mit dem XmlSerializer verwendet werden. Svcutil.exe können auch mithilfe des dataContractOnly Schalters ein XML-Schema aus Datenverträgen generieren.

Hinweis

Obwohl ASP.NET-Webdienste den XmlSerializer verwenden und der WCF-ASP.NET-Kompatibilitätsmodus WCF-Dienste das Verhalten von ASP.NET-Webdiensten nachahmen lässt, beschränkt die ASP.NET-Kompatibilitätsoption nicht auf die Verwendung des XmlSerializer. Man kann weiterhin das DataContractSerializer mit Diensten verwenden, die im ASP.NET-Kompatibilitätsmodus ausgeführt werden.

Dienstentwicklung

Um einen Dienst mithilfe von ASP.NET zu entwickeln, ist es üblich geworden, das WebService-Attribut einer Klasse hinzuzufügen, und das WebMethodAttribute-Attribut zu den Methoden dieser Klasse, die Vorgänge des Dienstes sein sollen, hinzufügen.

[WebService]
public class Service : T:System.Web.Services.WebService
{
    [WebMethod]
    public string Echo(string input)
    {
       return input;
    }
}

ASP.NET 2.0 hat die Option zum Hinzufügen des Attributs WebService und WebMethodAttribute zu einer Schnittstelle anstelle einer Klasse eingeführt und eine Klasse zum Implementieren der Schnittstelle geschrieben:

[WebService]
public interface IEcho
{
    [WebMethod]
    string Echo(string input);
}

public class Service : IEcho
{

   public string Echo(string input)
   {
        return input;
    }
}

Die Verwendung dieser Option ist zu bevorzugen, da die Schnittstelle mit dem WebService Attribut einen Vertrag für die Vorgänge darstellt, die vom Dienst ausgeführt werden, die mit verschiedenen Klassen wiederverwendet werden können, die diesen Vertrag auf unterschiedliche Weise implementieren können.

Ein WCF-Dienst wird durch Definieren eines oder mehrerer WCF-Endpunkte bereitgestellt. Ein Endpunkt wird durch eine Adresse, eine Bindung und einen Dienstvertrag definiert. Die Adresse definiert, wo sich der Dienst befindet. Die Bindung gibt an, wie mit dem Dienst kommuniziert werden soll. Der Dienstvertrag definiert die Vorgänge, die der Dienst ausführen kann.

Der Servicevertrag wird üblicherweise zuerst definiert, indem ServiceContractAttribute und OperationContractAttribute zu einer Schnittstelle hinzugefügt werden.

[ServiceContract]
public interface IEcho
{
     [OperationContract]
     string Echo(string input);
}

Die ServiceContractAttribute Schnittstelle gibt an, dass die Schnittstelle einen WCF-Dienstvertrag definiert und angibt OperationContractAttribute , welche( falls vorhanden) der Methoden der Schnittstelle Vorgänge des Dienstvertrags definieren.

Nachdem ein Dienstvertrag definiert wurde, wird er in einer Klasse implementiert, indem die Klasse die Schnittstelle implementiert, über die der Dienstvertrag definiert wird:

public class Service : IEcho
{
    public string Echo(string input)
    {
       return input;
    }
}

Eine Klasse, die einen Dienstvertrag implementiert, wird als Diensttyp in WCF bezeichnet.

Der nächste Schritt besteht darin, eine Adresse und eine Bindung einem Diensttyp zuzuordnen. Dies geschieht in der Regel in einer Konfigurationsdatei, entweder durch direktes Bearbeiten der Datei oder mithilfe eines konfigurations-Editors, der mit WCF bereitgestellt wird. Hier ist ein Beispiel für eine Konfigurationsdatei.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
     <system.serviceModel>
      <services>
      <service name="Service ">
       <endpoint
        address="EchoService"
        binding="basicHttpBinding"
        contract="IEchoService "/>
      </service>
      </services>
     </system.serviceModel>
</configuration>

Die Bindung gibt den Satz von Protokollen für die Kommunikation mit der Anwendung an. In der folgenden Tabelle sind die vom System bereitgestellten Bindungen aufgeführt, die allgemeine Optionen darstellen.

Name Zweck
BasicHttpBinding Interoperabilität mit Webdiensten und Clients, die die WS-BasicProfile 1.1 und Basic Security Profile 1.0 unterstützen.
WSHttpBinding Interoperabilität mit Webdiensten und Clients, die die WS-*-Protokolle über HTTP unterstützen.
WSDualHttpBinding Duplex-HTTP-Kommunikation, durch die der Empfänger einer ersten Nachricht nicht direkt auf den ursprünglichen Absender antwortet, sondern kann eine beliebige Anzahl von Antworten über einen bestimmten Zeitraum übertragen, indem HTTP in Übereinstimmung mit WS-*-Protokollen verwendet wird.
WSFederationBinding HTTP-Kommunikation, bei der der Zugriff auf die Ressourcen eines Diensts basierend auf anmeldeinformationen gesteuert werden kann, die von einem explizit identifizierten Anmeldeinformationsanbieter ausgestellt wurden.
NetTcpBinding Sichere, zuverlässige, leistungsstarke Kommunikation zwischen WCF-Softwareentitäten in einem Netzwerk.
NetNamedPipeBinding Sichere, zuverlässige, leistungsstarke Kommunikation zwischen WCF-Softwareentitäten auf demselben Computer.
NetMsmqBinding Kommunikation zwischen WCF-Softwareentitäten mithilfe von MSMQ.
MsmqIntegrationBinding Kommunikation zwischen einer WCF-Softwareentität und einer anderen Softwareentität mithilfe von MSMQ.
NetPeerTcpBinding Kommunikation zwischen WCF-Softwareentitäten mithilfe von Windows-Peer-zu-Peer-Netzwerken.

Die vom System bereitgestellte Bindung BasicHttpBindingenthält die von ASP.NET Webdiensten unterstützten Protokolle.

Benutzerdefinierte Bindungen für WCF-Anwendungen werden ganz einfach als Sammlungen der Bindungselementklassen definiert, die WCF zum Implementieren einzelner Protokolle verwendet. Neue Bindungselemente können geschrieben werden, um zusätzliche Protokolle darzustellen.

Das interne Verhalten von Diensttypen kann mithilfe der Eigenschaften einer Klassenfamilie angepasst werden, die als Verhaltensweisen bezeichnet wird. Hier wird die ServiceBehaviorAttribute Klasse verwendet, um anzugeben, dass der Diensttyp multithreadiert werden soll.

[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple)]
public class DerivativesCalculatorServiceType: IDerivativesCalculator

Einige Verhaltensweisen, wie z. B. ServiceBehaviorAttribute, sind Attribute. Andere, die Eigenschaften haben, welche von Administratoren festgelegt werden sollen, können in der Konfiguration der Anwendung geändert werden.

In Programmierdiensttypen wird häufig die OperationContext Klasse verwendet. Die statische Current Eigenschaft bietet Zugriff auf Informationen zum Kontext, in dem ein Vorgang ausgeführt wird. OperationContext ähnelt sowohl den HttpContext- als auch den ContextUtil-Klassen.

Gastgeberrolle

ASP.NET Webdienste werden in einer Klassenbibliotheksassembly kompiliert. Eine Datei, die als Dienstdatei bezeichnet wird, wird bereitgestellt, die die Erweiterung ASMX enthält und eine @ WebService Direktive enthält, die die Klasse identifiziert, die den Code für den Dienst und die Assembly enthält, in der sie sich befindet.

<%@ WebService Language="C#" Class="Service,ServiceAssembly" %>

Die Dienstdatei wird in einen ASP.NET Anwendungsstamm in den Internetinformationsdiensten (IIS) kopiert, und die Assembly wird in das Unterverzeichnis "\bin" dieses Anwendungsstamms kopiert. Auf die Anwendung kann dann über die URL (Uniform Resource Locator) der Dienstdatei im Anwendungsstamm zugegriffen werden.

WCF-Dienste können problemlos in IIS 5.1 oder 6.0, dem Windows-Prozessaktivierungsdienst (WAS) gehostet werden, der als Teil von IIS 7.0 und in einer beliebigen .NET-Anwendung bereitgestellt wird. Um einen Dienst in IIS 5.1 oder 6.0 zu hosten, muss der Dienst HTTP als Kommunikationstransportprotokoll verwenden.

Führen Sie die folgenden Schritte aus, um einen Dienst in IIS 5.1, 6.0 oder in WAS zu hosten:

  1. Kompilieren Sie den Diensttyp in eine Assembly der Klassenbibliothek.

  2. Erstellen Sie eine Dienstdatei mit einer SVC-Erweiterung mit einer @ ServiceHost Direktive, um den Diensttyp zu identifizieren:

    <%@ServiceHost language="c#" Service="MyService" %>

  3. Kopieren Sie die Dienstdatei in ein virtuelles Verzeichnis und die Assembly in das Unterverzeichnis "\bin" dieses virtuellen Verzeichnisses.

  4. Kopieren Sie die Konfigurationsdatei in das virtuelle Verzeichnis, und nennen Sie sie Web.config.

Auf die Anwendung kann dann über die URL der Dienstdatei im Anwendungsstamm zugegriffen werden.

Um einen WCF-Dienst in einer .NET-Anwendung zu hosten, kompilieren Sie den Diensttyp in eine Klassenbibliotheksassembly, auf die von der Anwendung verwiesen wird, und programmieren Sie die Anwendung so, dass der Dienst mithilfe der ServiceHost Klasse gehostet wird. Im Folgenden sehen Sie ein Beispiel für die grundlegende Programmierung, die erforderlich ist:

string httpBaseAddress = "http://www.contoso.com:8000/";
string tcpBaseAddress = "net.tcp://www.contoso.com:8080/";

Uri httpBaseAddressUri = new Uri(httpBaseAddress);
Uri tcpBaseAddressUri = new Uri(tcpBaseAddress);

Uri[] baseAddresses = new Uri[] {
 httpBaseAddressUri,
 tcpBaseAddressUri};

using(ServiceHost host = new ServiceHost(
typeof(Service), //"Service" is the name of the service type baseAddresses))
{
     host.Open();

     […] //Wait to receive messages
     host.Close();
}

In diesem Beispiel wird gezeigt, wie Adressen für ein oder mehrere Transportprotokolle bei der Konstruktion eines ServiceHost festgelegt werden. Diese Adressen werden als Basisadressen bezeichnet.

Die für jeden Endpunkt eines WCF-Diensts angegebene Adresse ist eine Adresse relativ zu einer Basisadresse des Endpunkthosts. Der Host kann eine Basisadresse für jedes Kommunikationstransportprotokoll haben. In der Beispielkonfiguration in der vorherigen Konfigurationsdatei verwendet der BasicHttpBinding für den Endpunkt ausgewählte HTTP als Transportprotokoll, sodass die Adresse des Endpunkts EchoServicerelativ zur HTTP-Basisadresse des Hosts ist. Im Fall des Hosts im vorherigen Beispiel lautet http://www.contoso.com:8000/die HTTP-Basisadresse . Bei einem Dienst, der in IIS oder WAS gehostet wird, ist die Basisadresse die URL der Dienstdatei des Diensts.

Nur dienste, die in IIS oder WAS gehostet werden und ausschließlich mit HTTP als Transportprotokoll konfiguriert sind, können verwendet werden, um WCF ASP.NET Kompatibilitätsmodusoption zu verwenden. Das Aktivieren dieser Option erfordert die folgenden Schritte.

  1. Der Programmierer muss das AspNetCompatibilityRequirementsAttribute Attribut dem Diensttyp hinzufügen und angeben, dass ASP.NET Kompatibilitätsmodus entweder zulässig oder erforderlich ist.

    [System.ServiceModel.Activation.AspNetCompatibilityRequirements(
          RequirementsMode=AspNetCompatibilityRequirementsMode.Require)]
    public class DerivativesCalculatorServiceType: IDerivativesCalculator
    
  2. Der Administrator muss die Anwendung so konfigurieren, dass der kompatibilitätsmodus ASP.NET verwendet wird.

    <configuration>
         <system.serviceModel>
          <services>
          […]
          </services>
          <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
        </system.serviceModel>
    </configuration>
    

    WCF-Anwendungen können auch so konfiguriert werden, dass .asmx als Erweiterung für ihre Dienstdateien anstelle von .svc verwendet wird.

    <system.web>
         <compilation>
          <compilation debug="true">
          <buildProviders>
           <remove extension=".asmx"/>
           <add extension=".asmx"
            type="System.ServiceModel.ServiceBuildProvider,
            System.ServiceModel,
            Version=3.0.0.0,
            Culture=neutral,
            PublicKeyToken=b77a5c561934e089" />
          </buildProviders>
          </compilation>
         </compilation>
    </system.web>
    

    Diese Option kann Ihnen ersparen, Clients ändern zu müssen, die so konfiguriert sind, dass sie die URLs von .asmx-Dienstdateien verwenden, wenn ein Dienst auf die Nutzung von WCF umgestellt wird.

Cliententwicklung

Clients für ASP.NET Webdienste werden mithilfe des Befehlszeilentools WSDL.exegeneriert, das die URL der ASMX-Datei als Eingabe bereitstellt. Das von WCF bereitgestellte Tool ist serviceModel Metadata Utility Tool (Svcutil.exe). Es generiert ein Codemodul mit der Definition des Dienstvertrags und der Definition einer WCF-Clientklasse. Außerdem wird eine Konfigurationsdatei mit der Adresse und Bindung des Diensts generiert.

Bei der Programmierung eines Clients eines Remotediensts ist es in der Regel ratsam, nach einem asynchronen Muster zu programmieren. Der vom tool WSDL.exe generierte Code stellt standardmäßig sowohl ein synchrones als auch ein asynchrones Muster bereit. Der vom ServiceModel Metadata Utility Tool (Svcutil.exe) generierte Code kann für beide Muster bereitgestellt werden. Es stellt standardmäßig das synchrone Muster bereit. Wenn das Tool mit dem /async Switch ausgeführt wird, stellt der generierte Code das asynchrone Muster bereit.

Es gibt keine Garantie dafür, dass Namen in den WCF-Clientklassen, die vom WSDL.exe-Tool von ASP.NET generiert werden, standardmäßig mit den Namen in WCF-Clientklassen übereinstimmen, die vom Svcutil.exe-Tool generiert werden. Insbesondere die Namen der Eigenschaften von Klassen, die mithilfe des XmlSerializer serialisiert werden müssen, erhalten standardmäßig das Suffix 'Property' im von Tool Svcutil.exe generierten Code, was bei Tool WSDL.exe nicht der Fall ist.

Nachrichtendarstellung

Die Kopfzeilen der SOAP-Nachrichten, die von ASP.NET Webdiensten gesendet und empfangen werden, können angepasst werden. Eine Klasse wird von SoapHeader abgeleitet, um die Struktur des Headers zu definieren, und anschließend wird SoapHeaderAttribute verwendet, um das Vorhandensein des Headers anzugeben.

public class SomeProtocol : SoapHeader
{
     public long CurrentValue;
     public long Total;
}

[WebService]
public interface IEcho
{
     SomeProtocol ProtocolHeader
     {
      get;
     set;
     }

     [WebMethod]
     [SoapHeader("ProtocolHeader")]
     string PlaceOrders(PurchaseOrderType order);
}

public class Service: WebService, IEcho
{
     private SomeProtocol protocolHeader;

     public SomeProtocol ProtocolHeader
     {
         get
         {
              return this.protocolHeader;
         }

         set
         {
              this.protocolHeader = value;
         }
     }

     string PlaceOrders(PurchaseOrderType order)
     {
         long currentValue = this.protocolHeader.CurrentValue;
     }
}

Der WCF stellt die Attribute, , MessageContractAttributeund MessageHeaderAttribute zur Beschreibung der Struktur der SOAP-Nachrichten bereit, MessageBodyMemberAttributedie von einem Dienst gesendet und empfangen werden.

[DataContract]
public class SomeProtocol
{
     [DataMember]
     public long CurrentValue;
     [DataMember]
     public long Total;
}

[DataContract]
public class Item
{
     [DataMember]
     public string ItemNumber;
     [DataMember]
     public decimal Quantity;
     [DataMember]
     public decimal UnitPrice;
}

[MessageContract]
public class ItemMessage
{
     [MessageHeader]
     public SomeProtocol ProtocolHeader;
     [MessageBody]
     public Item Content;
}

[ServiceContract]
public interface IItemService
{
     [OperationContract]
     public void DeliverItem(ItemMessage itemMessage);
}

Diese Syntax liefert eine explizite Darstellung der Struktur der Nachrichten, während die Struktur von Nachrichten durch den Code eines ASP.NET Webdiensts impliziert wird. Außerdem werden in der ASP.NET Syntax Nachrichtenkopfzeilen als Eigenschaften des Diensts dargestellt, z. B. die ProtocolHeader Eigenschaft im vorherigen Beispiel, während sie in der WCF-Syntax genauer als Eigenschaften von Nachrichten dargestellt werden. Außerdem ermöglicht WCF, dass Nachrichtenkopfzeilen zur Konfiguration von Endpunkten hinzugefügt werden.

<service name="Service ">
     <endpoint
      address="EchoService"
      binding="basicHttpBinding"
      contract="IEchoService ">
      <headers>
      <dsig:X509Certificate
       xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
       ...
      </dsig:X509Certificate>
      </headers>
     </endpoint>
</service>

Mit dieser Option können Sie Verweise auf infrastrukturelle Protokollheader im Code für einen Client oder Dienst vermeiden: Die Header werden den Nachrichten hinzugefügt, basierend auf der Konfiguration des Endpunkts.

Dienstbeschreibung

Das Ausgeben einer HTTP GET-Anforderung für die ASMX-Datei eines ASP.NET-Webdiensts mit der Abfrage WSDL bewirkt, dass ASP.NET WSDL zum Beschreiben des Diensts generiert. Sie gibt die WSDL als Antwort auf die Anforderung zurück.

ASP.NET 2.0 ermöglichte es, zu überprüfen, ob ein Dienst mit dem Basic Profile 1.1 der Web-Services-Interoperability Organisation (WS-I) kompatibel ist, und einen Anspruch einzufügen, dass der Dienst in seine WSDL kompatibel ist. Dies erfolgt mithilfe der Parameter ConformsTo und EmitConformanceClaims des WebServiceBindingAttribute Attributs.

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(
     ConformsTo = WsiProfiles.BasicProfile1_1,
     EmitConformanceClaims=true)]
public interface IEcho

Die WSDL, die ASP.NET für einen Dienst generiert, kann angepasst werden. Anpassungen werden durch Erstellen einer abgeleiteten Klasse zum Hinzufügen von ServiceDescriptionFormatExtension Elementen zur WSDL erstellt.

Das Ausgeben einer HTTP GET-Anforderung mit der Abfrage WSDL für die SVC-Datei eines WCF-Diensts mit einem HTTP-Endpunkt, der in IIS 51, 6.0 oder WAS gehostet wird, bewirkt, dass WCF mit WSDL reagiert, um den Dienst zu beschreiben. Das Ausgeben einer HTTP GET-Anforderung mit der Abfrage WSDL an die HTTP-Basisadresse eines Diensts, der in einer .NET-Anwendung gehostet wird, hat die gleiche Auswirkung, wenn "httpGetEnabled" auf "true" festgelegt ist.

Allerdings antwortet WCF auch auf WS-MetadataExchange-Anforderungen mit WSDL, die zum Beschreiben eines Diensts generiert wird. ASP.NET Webdienste verfügen nicht über integrierte Unterstützung für WS-MetadataExchange Anforderungen.

Die von WCF generierte WSDL kann umfassend angepasst werden. Die ServiceMetadataBehavior Klasse bietet einige Möglichkeiten zum Anpassen der WSDL. Der WCF kann auch so konfiguriert werden, dass nicht WSDL generiert wird, sondern eine statische WSDL-Datei unter einer bestimmten URL verwendet wird.

<behaviors>
     <behavior name="DescriptionBehavior">
     <metadataPublishing
      enableMetadataExchange="true"
      enableGetWsdl="true"
      enableHelpPage="true"
      metadataLocation=
      "http://localhost/DerivativesCalculatorService/Service.WSDL"/>
     </behavior>
</behaviors>

Ausnahmebehandlung

In ASP.NET Webdiensten werden unbehandelte Ausnahmen als SOAP-Fehler an Clients zurückgegeben. Sie können instanzen der SoapException Klasse auch explizit auslösen und mehr Kontrolle über den Inhalt des SOAP-Fehlers haben, der an den Client übertragen wird.

In WCF-Diensten werden nicht behandelte Ausnahmen nicht als SOAP-Fehler an Clients zurückgegeben, um zu verhindern, dass vertrauliche Informationen versehentlich über die Ausnahmen verfügbar gemacht werden. Es wird eine Konfigurationseinstellung bereitgestellt, um unbehandelte Ausnahmen für den Zweck des Debuggens an Clients zurückzugeben.

Um SOAP-Fehler an Clients zurückzugeben, können Sie Instanzen des generischen Typs FaultException<TDetail> auslösen, indem Sie den Datentyp des Datenvertrags (Data Contract) als generischen Typ verwenden. Sie können auch Attribute zu Operationen hinzufügen FaultContractAttribute, um die Fehler anzugeben, die eine Operation möglicherweise liefern kann.

[DataContract]
public class MathFault
{
     [DataMember]
     public string operation;
     [DataMember]
     public string problemType;
}

[ServiceContract]
public interface ICalculator
{
     [OperationContract]
     [FaultContract(typeof(MathFault))]
     int Divide(int n1, int n2);
}

Dies führt dazu, dass die möglichen Fehler in der WSDL für den Dienst angekündigt werden, sodass Clientprogrammierer antizipieren können, welche Fehler aus einem Vorgang resultieren können, und die entsprechenden Catch-Anweisungen schreiben.

try
{
     result = client.Divide(value1, value2);
}
catch (FaultException<MathFault> e)
{
 Console.WriteLine("FaultException<MathFault>: Math fault while doing "
  + e.Detail.operation
  + ". Problem: "
  + e.Detail.problemType);
}

Zustandsverwaltung

Die Klasse, die zum Implementieren eines ASP.NET-Webdienstes verwendet wird, kann von WebService abgeleitet werden.

public class Service : WebService, IEcho
{

 public string Echo(string input)
 {
  return input;
 }
}

In diesem Fall kann die Klasse so programmiert werden, dass die Context-Eigenschaft der WebService Basisklasse für den Zugriff auf ein HttpContext Objekt verwendet wird. Das HttpContext Objekt kann verwendet werden, um Anwendungsstatusinformationen mithilfe der Application-Eigenschaft zu aktualisieren und abzurufen, und kann verwendet werden, um Sitzungsstatusinformationen mithilfe der Session-Eigenschaft zu aktualisieren und abzurufen.

ASP.NET bietet umfassende Funktionen zur Bestimmung des tatsächlichen Speicherorts der Sitzungszustandsinformationen, auf die mithilfe der Sitzungseigenschaft von HttpContext zugegriffen wird. Er kann in Cookies, in einer Datenbank, im Speicher des aktuellen Servers oder im Speicher eines bestimmten Servers gespeichert werden. Die Auswahl erfolgt in der Konfigurationsdatei des Diensts.

Wcf stellt erweiterbare Objekte für die Zustandsverwaltung bereit. Erweiterbare Objekte sind Objekte, die IExtensibleObject<T> implementiert. Die wichtigsten erweiterbaren Objekte sind ServiceHostBase und InstanceContext. ServiceHostBase ermöglicht es Ihnen, den Zustand beizubehalten, dass alle Instanzen aller Diensttypen auf demselben Host zugreifen können, während InstanceContext Sie den Zustand beibehalten können, auf den von jedem Code zugegriffen werden kann, der innerhalb derselben Instanz eines Diensttyps ausgeführt wird.

Hier wird der Diensttyp TradingSystem durch ein ServiceBehaviorAttribute charakterisiert, das angibt, dass alle Aufrufe derselben WCF-Clientinstanz an dieselbe Instanz des Diensttyps weitergeleitet werden.

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class TradingSystem: ITradingService

Die Klasse DealData definiert einen Zustand, auf den von jedem Code zugegriffen werden kann, der in derselben Instanz eines Diensttyps ausgeführt wird.

internal class DealData: IExtension<InstanceContext>
{
 public string DealIdentifier = null;
 public Trade[] Trades = null;
}

Im Code des Diensttyps, der einen der Vorgänge des Dienstvertrags implementiert, wird dem Status der aktuellen Instanz des Diensttyps ein DealData Statusobjekt hinzugefügt.

string ITradingService.BeginDeal()
{
 string dealIdentifier = Guid.NewGuid().ToString();
 DealData state = new DealData(dealIdentifier);
 OperationContext.Current.InstanceContext.Extensions.Add(state);
 return dealIdentifier;
}

Dieses Statusobjekt kann dann vom Code abgerufen und geändert werden, der eine andere der Vorgänge des Servicevertrags implementiert.

void ITradingService.AddTrade(Trade trade)
{
 DealData dealData =  OperationContext.Current.InstanceContext.Extensions.Find<DealData>();
 dealData.AddTrade(trade);
}

Während ASP.NET die Kontrolle darüber bietet, wo Zustandsinformationen in der HttpContext Klasse tatsächlich gespeichert werden, bietet WCF, zumindest in der ursprünglichen Version, keine Kontrolle darüber, wo erweiterbare Objekte gespeichert werden. Dies ist der beste Grund für die Auswahl des ASP.NET Kompatibilitätsmodus für einen WCF-Dienst. Wenn die konfigurierbare Zustandsverwaltung zwingend erforderlich ist, können Sie mit der Auswahl für den ASP.NET Kompatibilitätsmodus die Funktionen der HttpContext Klasse genau so verwenden, wie sie in ASP.NET verwendet werden, und außerdem, um zu konfigurieren, wo Zustandsinformationen mithilfe der HttpContext Klasse gespeichert werden.

Sicherheit

Die Optionen zum Sichern von ASP.NET Webdiensten sind diejenigen zum Sichern einer IIS-Anwendung. Da WCF-Anwendungen nicht nur in IIS, sondern auch in einer beliebigen ausführbaren .NET-Datei gehostet werden können, müssen die Optionen zum Sichern von WCF-Anwendungen unabhängig von den Iis-Einrichtungen erfolgen. Die für ASP.NET Webdienste bereitgestellten Einrichtungen stehen jedoch auch für WCF-Dienste zur Verfügung, die im ASP.NET Kompatibilitätsmodus ausgeführt werden.

Sicherheit: Authentifizierung

IIS bietet Funktionen zum Steuern des Zugriffs auf Anwendungen, mit denen Sie entweder anonymen Zugriff oder eine Vielzahl von Authentifizierungsmodi auswählen können: Windows-Authentifizierung, Digestauthentifizierung, Standardauthentifizierung und .NET Passport-Authentifizierung. Die Windows-Authentifizierungsoption kann verwendet werden, um den Zugriff auf ASP.NET Webdienste zu steuern. Wenn WCF-Anwendungen jedoch in IIS gehostet werden, muss IIS so konfiguriert werden, dass anonymer Zugriff auf die Anwendung zulässig ist, damit die Authentifizierung von WCF selbst verwaltet werden kann, was die Windows-Authentifizierung unter verschiedenen anderen Optionen unterstützt. Die anderen integrierten Optionen umfassen Benutzernamentoken, X.509-Zertifikate, SAML-Token und CardSpace-Karte, aber auch benutzerdefinierte Authentifizierungsmechanismen können definiert werden.

Sicherheit: Identitätsanmaßung

ASP.NET stellt ein Identitätselement bereit, mit dem ein ASP.NET-Webdienst einen bestimmten Benutzer oder jeden Benutzer, dessen Anmeldedaten mit der aktuellen Anfrage bereitgestellt werden, imitieren kann. Dieses Element kann zur Konfiguration des Identitätswechsels in WCF-Anwendungen verwendet werden, die im ASP.NET-Kompatibilitätsmodus ausgeführt werden.

Das WCF-Konfigurationssystem stellt ein eigenes Identitätselement zur Verfügung, um einen bestimmten Benutzer zur Nachahmung zu benennen. Außerdem können WCF-Clients und -Dienste unabhängig für den Identitätswechsel konfiguriert werden. Clients können so konfiguriert werden, dass sie den aktuellen Benutzer nachahmen, wenn sie Anforderungen übermitteln.

<behaviors>
     <behavior name="DerivativesCalculatorClientBehavior">
      <clientCredentials>
      <windows allowedImpersonationLevel="Impersonation"/>
      </clientCredentials>
     </behavior>
</behaviors>

Dienstvorgänge können dafür konfiguriert werden, einen Identitätswechsel für einen beliebigen Benutzer durchzuführen, dessen Anmeldeinformationen in der aktuellen Anforderung angegeben werden.

[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public void Receive(Message input)

Sicherheit: Autorisierung mithilfe von Zugriffssteuerungslisten

Zugriffssteuerungslisten (ACCESS Control Lists, ACLs) können verwendet werden, um den Zugriff auf ASMX-Dateien einzuschränken. ACLs in WCF-SVC-Dateien werden jedoch ignoriert, außer im ASP.NET Kompatibilitätsmodus.

Sicherheit: Rollenbasierte Autorisierung

Die IIS-Windows-Authentifizierungsoption kann in Verbindung mit dem Autorisierungselement verwendet werden, das von der ASP.NET Konfigurationssprache bereitgestellt wird, um die rollenbasierte Autorisierung für ASP.NET Webdienste basierend auf den Windows-Gruppen zu erleichtern, denen Benutzer zugewiesen sind. ASP.NET 2.0 hat einen allgemeineren rollenbasierten Autorisierungsmechanismus eingeführt: Rollenanbieter.

Rollenanbieter sind Klassen, die alle eine grundlegende Schnittstelle implementieren, um nach den Rollen zu fragen, denen ein Benutzer zugewiesen ist, aber jeder Rollenanbieter weiß, wie diese Informationen aus einer anderen Quelle abgerufen werden. ASP.NET 2.0 stellt einen Rollenanbieter bereit, der Rollenzuweisungen aus einer Microsoft SQL Server-Datenbank abrufen kann, und eine andere, die Rollenzuweisungen aus dem Windows Server 2003-Autorisierungs-Manager abrufen kann.

Der Rollenanbietermechanismus kann tatsächlich unabhängig von ASP.NET in jeder .NET-Anwendung verwendet werden, einschließlich einer WCF-Anwendung. Die folgende Beispielkonfiguration für eine WCF-Anwendung zeigt, wie die Verwendung eines ASP.NET Rollenanbieters als Option mittels des ServiceAuthorizationBehavior ausgewählt wird.

<system.serviceModel>
     <services>
         <service name="Service.ResourceAccessServiceType"
             behaviorConfiguration="ServiceBehavior">
             <endpoint
              address="ResourceAccessService"
              binding="wsHttpBinding"
              contract="Service.IResourceAccessContract"/>
         </service>
     </services>
     <behaviors>
       <behavior name="ServiceBehavior">
       <serviceAuthorization principalPermissionMode="UseAspNetRoles"/>
      </behavior>
     </behaviors>
</system.serviceModel>

Sicherheit: Anspruchsbasierte Autorisierung

Eine der wichtigsten Innovationen von WCF ist die gründliche Unterstützung für die Autorisierung des Zugriffs auf geschützte Ressourcen basierend auf Ansprüchen. Ansprüche bestehen aus einem Typ, einem Rechten und einem Wert, z. B. einer Treiberlizenz. Es macht eine Reihe von Ansprüchen über den Bearer, von denen eines das Geburtsdatum des Trägers ist. Die Art dieses Anspruchs ist Geburtsdatum, während der Wert des Anspruchs das Geburtsdatum des Fahrers ist. Das Recht, das ein Anspruch dem Inhaber verleiht, legt fest, was der Inhaber mit dem Wert des Anspruchs tun kann. Im Falle der Behauptung des Geburtsdatums des Fahrers besteht das Recht im Besitz: Der Fahrer besitzt dieses Geburtsdatum, kann es aber nicht ändern. Die anspruchsbasierte Autorisierung schließt die rollenbasierte Autorisierung ein, da Rollen ein Anspruchstyp sind.

Bei der anspruchbasierten Autorisierung wird ein Anspruchsatz mit den Zugriffsanforderungen des Vorgangs verglichen. Dabei wird der Zugriff auf den Vorgang abhängig vom Ergebnis dieses Vergleichs gewährt oder verweigert. In WCF können Sie eine Klasse angeben, die zum Ausführen der anspruchsbasierten Autorisierung verwendet werden soll, indem Sie der ServiceAuthorizationManager Eigenschaft von ServiceAuthorizationBehaviorerneut einen Wert zuweisen.

<behaviors>
     <behavior name='ServiceBehavior'>
     <serviceAuthorization
     serviceAuthorizationManagerType=
                   'Service.AccessChecker, Service' />
     </behavior>
</behaviors>

Klassen, die zum Ausführen der anspruchsbasierten Autorisierung verwendet werden, müssen von ServiceAuthorizationManager abgeleitet werden, die nur eine Methode, AccessCheck(), zum Überschreiben besitzt. WCF ruft diese Methode auf, wenn ein Vorgang des Diensts aufgerufen wird, und stellt ein OperationContext Objekt bereit, das über die Ansprüche für den Benutzer in seiner ServiceSecurityContext.AuthorizationContext Eigenschaft verfügt. WCF übernimmt die Zusammenstellung von Ansprüchen über den Benutzer basierend auf dem Sicherheitstoken, das der Benutzer zur Authentifizierung bereitgestellt hat, und überlässt es dann der Aufgabe, zu bewerten, ob diese Ansprüche für den betreffenden Vorgang ausreichen.

Dass WCF automatisch Ansprüche aus jeder Art von Sicherheitstoken zusammenfügt, ist eine sehr wichtige Innovation, da der Code für die Autorisierung basierend auf den Ansprüchen vollständig unabhängig vom Authentifizierungsmechanismus wird. Im Gegensatz dazu ist die Autorisierung mit ACLs oder Rollen in ASP.NET eng mit der Windows-Authentifizierung verknüpft.

Sicherheit: Vertraulichkeit

Die Vertraulichkeit von Nachrichten, die mit ASP.NET Webdiensten ausgetauscht werden, kann auf Transportebene sichergestellt werden, indem die Anwendung in IIS für die Verwendung des Secure Hypertext Transfer Protocol (HTTPS) konfiguriert wird. Dasselbe kann für WCF-Anwendungen erfolgen, die in IIS gehostet werden. WCF-Anwendungen, die außerhalb von IIS gehostet werden, können jedoch auch für die Verwendung eines sicheren Transportprotokolls konfiguriert werden. Wichtiger ist, dass WCF-Anwendungen auch so konfiguriert werden können, dass die Nachrichten gesichert werden, bevor sie transportiert werden, mithilfe des WS-Security-Protokolls. Wenn Sie nur den Textkörper einer Nachricht mithilfe von WS-Security sichern, können Sie sie vertraulich über Vermittler übertragen, bevor sie ihr endgültiges Ziel erreichen.

Globalisierung

Mit der ASP.NET-Konfigurationssprache können Sie die Kultur für einzelne Dienste angeben. Die WCF unterstützt diese Konfigurationseinstellung nicht, außer im ASP.NET Kompatibilitätsmodus. Um einen WCF-Dienst zu lokalisieren, der nicht ASP.NET Kompatibilitätsmodus verwendet, kompilieren Sie den Diensttyp in kulturspezifische Assemblys und verfügen über separate kulturspezifische Endpunkte für jede kulturspezifische Assembly.

Siehe auch