Condividi tramite


Confronto tra i Servizi Web di ASP.NET e WCF basato sullo sviluppo

Windows Communication Foundation (WCF) dispone di un'opzione ASP.NET modalità di compatibilità per abilitare le applicazioni WCF da programmare e configurare come ASP.NET servizi Web e simularne il comportamento. Le sezioni seguenti confrontano ASP.NET servizi Web e WCF in base a ciò che è necessario per sviluppare applicazioni usando entrambe le tecnologie.

Rappresentazione dei dati

Lo sviluppo di un servizio Web con ASP.NET inizia in genere con la definizione di qualsiasi tipo di dati complesso che il servizio deve usare. ASP.NET si basa su XmlSerializer per convertire i dati rappresentati da tipi .NET Framework in XML per la trasmissione da o verso un servizio e per convertire i dati ricevuti come XML in oggetti .NET Framework. La definizione dei tipi di dati complessi che un servizio ASP.NET deve usare richiede la definizione di classi .NET Framework che XmlSerializer possono serializzare da e verso XML. Tali classi possono essere scritte manualmente o generate da definizioni dei tipi in XML Schema usando l'utilità di supporto per Schemi XML/Tipi di Dati della riga di comando, xsd.exe.

Di seguito è riportato un elenco di problemi principali da conoscere quando si definiscono classi .NET Framework che XmlSerializer possono serializzare da e verso XML:

  • Solo i campi e le proprietà pubblici degli oggetti .NET Framework vengono convertiti in XML.

  • Le istanze delle classi di raccolta possono essere serializzate in XML solo se le classi implementano l'interfaccia IEnumerable o ICollection .

  • Le classi che implementano l'interfaccia IDictionary , ad esempio Hashtable, non possono essere serializzate in XML.

  • I numerosi tipi di attributo nello System.Xml.Serialization spazio dei nomi possono essere aggiunti a una classe .NET Framework e ai relativi membri per controllare il modo in cui le istanze della classe sono rappresentate in XML.

Lo sviluppo di applicazioni WCF inizia in genere anche con la definizione di tipi complessi. È possibile creare WCF per usare gli stessi tipi di .NET Framework dei servizi Web ASP.NET.

WCFDataContractAttribute e DataMemberAttribute possono essere aggiunti ai tipi .NET Framework per indicare che le istanze del tipo devono essere serializzate in XML e quali campi o proprietà particolari del tipo devono essere serializzati, come illustrato nel codice di esempio seguente.

//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;
          }
     }
}

DataContractAttribute Indica che devono essere serializzati zero o più campi o proprietà di un tipo, mentre indica DataMemberAttribute che deve essere serializzato un campo o una proprietà specifica. Può DataContractAttribute essere applicato a una classe o a una struttura. DataMemberAttribute Può essere applicato a un campo o a una proprietà e i campi e le proprietà a cui viene applicato l'attributo possono essere pubblici o privati. Le istanze di tipi a cui è applicato DataContractAttribute sono denominate contratti di dati in WCF. Vengono serializzati in XML usando DataContractSerializer.

Di seguito è riportato un elenco delle differenze importanti tra l'uso di DataContractSerializer e l'uso di XmlSerializer e i vari attributi dello spazio dei nomi System.Xml.Serialization.

  • Gli attributi di XmlSerializer e dello spazio dei nomi System.Xml.Serialization sono progettati per consentire di mappare i tipi .NET Framework a qualsiasi tipo valido definito in XML Schema e di conseguenza forniscono un controllo molto preciso sul modo in cui un tipo viene rappresentato in XML. DataContractSerializer e DataContractAttributeDataMemberAttribute forniscono un controllo molto minimo sul modo in cui un tipo viene rappresentato in XML. È possibile specificare solo gli spazi dei nomi e i nomi utilizzati per rappresentare il tipo e i relativi campi o proprietà nel codice XML e la sequenza in cui i campi e le proprietà vengono visualizzati nel codice XML:

    [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;
    }
    

    Tutto il resto della struttura del codice XML usato per rappresentare il tipo .NET è determinato dall'oggetto DataContractSerializer.

  • Non consentendo molto controllo sul modo in cui un tipo deve essere rappresentato in XML, il processo di serializzazione diventa estremamente prevedibile per DataContractSerializere, di conseguenza, più facile da ottimizzare. Un vantaggio pratico del design di DataContractSerializer è una prestazione migliorata, circa il dieci per cento in più.

  • Gli attributi da utilizzare con XmlSerializer non indicano quali campi o proprietà del tipo vengono serializzati in XML, mentre l'oggetto DataMemberAttribute da utilizzare con DataContractSerializer mostra in modo esplicito quali campi o proprietà vengono serializzati. Pertanto, i contratti dati sono contratti espliciti sulla struttura dei dati che un'applicazione deve inviare e ricevere.

  • XmlSerializer Può convertire solo i membri pubblici di un oggetto .NET in XML, che DataContractSerializer può convertire i membri di oggetti in XML indipendentemente dai modificatori di accesso di tali membri.

  • Proposto miglioramento: Grazie alla possibilità di serializzare i membri non pubblici dei tipi in XML, il DataContractSerializer incontra meno restrizioni sulla varietà di tipi .NET che può serializzare in XML. In particolare, può tradursi in tipi XML come Hashtable che implementano l'interfaccia IDictionary . DataContractSerializer è molto più probabile che sia in grado di serializzare le istanze di qualsiasi tipo .NET preesistente in XML senza dover modificare la definizione del tipo o sviluppare un wrapper.

  • Un'altra conseguenza della possibilità di DataContractSerializer di accedere ai membri non pubblici di un tipo è che DataContractSerializer richiede piena attendibilità, mentre no. L'autorizzazione di accesso codice con fiducia completa consente l'accesso completo a tutte le risorse su una macchina che possono essere accessibili utilizzando le credenziali sotto cui viene eseguito il codice. Questa opzione deve essere usata con attenzione perché il codice completamente attendibile accede a tutte le risorse nel computer.

  • DataContractSerializer Incorpora alcuni supporti per il controllo delle versioni:

    • Il DataMemberAttribute ha una IsRequired proprietà a cui è possibile assegnare un valore false per i membri che sono stati aggiunti alle nuove versioni di un contratto dati e che non erano presenti nelle versioni precedenti, consentendo così alle applicazioni con la versione più recente del contratto di poter elaborare le versioni precedenti.

    • Avendo un contratto dati che implementa l'interfaccia IExtensibleDataObject, è possibile consentire a DataContractSerializer di trasferire membri definiti nelle versioni più recenti di un contratto dati attraverso applicazioni con versioni precedenti del contratto.

Nonostante tutte le differenze, il codice XML in cui serializza XmlSerializer un tipo per impostazione predefinita è semanticamente identico al codice XML in cui serializza DataContractSerializer un tipo, purché lo spazio dei nomi per il codice XML sia definito in modo esplicito. La classe seguente, che ha attributi da usare con entrambi i serializzatori, viene convertita in xml semanticamente identico da XmlSerializer e da DataContractAttribute:

[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;
}

Windows Software Development Kit (SDK) include uno strumento da riga di comando denominato ServiceModel Metadata Utility Tool (Svcutil.exe). Analogamente allo strumento xsd.exe usato con i servizi Web ASP.NET, Svcutil.exe può generare definizioni di tipi di dati .NET da XML Schema. I tipi sono contratti dati se l'oggetto DataContractSerializer può generare codice XML nel formato definito da XML Schema; in caso contrario, sono destinati alla serializzazione utilizzando .XmlSerializer Svcutil.exe può anche generare un XML Schema dai contratti dati usando il relativo dataContractOnly commutatore.

Annotazioni

Anche se i servizi Web di ASP.NET usano la XmlSerializer, e la modalità ASP.NET di WCF fa sì che i servizi WCF simulino il comportamento dei servizi Web ASP.NET, l'opzione di compatibilità ASP.NET non limita al solo utilizzo di XmlSerializer. È comunque possibile usare DataContractSerializer con i servizi in esecuzione nella modalità di compatibilità ASP.NET.

Sviluppo di servizi

Per sviluppare un servizio usando ASP.NET, è consuetudine aggiungere l'attributo WebService a una classe e WebMethodAttribute a qualunque metodo di quella classe che deve essere un'operazione del servizio.

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

ASP.NET 2.0 ha introdotto l'opzione per aggiungere l'attributo WebService e WebMethodAttribute a un'interfaccia anziché a una classe e scrivere una classe per implementare l'interfaccia:

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

public class Service : IEcho
{

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

L'uso di questa opzione deve essere preferito, perché l'interfaccia con l'attributo WebService costituisce un contratto per le operazioni eseguite dal servizio che può essere riutilizzato con varie classi che potrebbero implementare lo stesso contratto in modi diversi.

Un servizio WCF viene fornito definendo uno o più endpoint WCF. Un endpoint è definito da un indirizzo, un binding e un contratto di servizio. L'indirizzo definisce dove si trova il servizio. Il collegamento specifica come comunicare con il servizio. Il contratto di servizio definisce le operazioni che il servizio può eseguire.

Il contratto di servizio viene in genere definito per primo, aggiungendo ServiceContractAttribute e OperationContractAttribute a un'interfaccia:

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

ServiceContractAttribute Specifica che l'interfaccia definisce un contratto di servizio WCF e indica OperationContractAttribute quale, se presente, dei metodi dell'interfaccia definiscono le operazioni del contratto di servizio.

Dopo aver definito un contratto di servizio, viene implementato in una classe, avendo la classe implementa l'interfaccia in base alla quale è definito il contratto di servizio:

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

Una classe che implementa un contratto di servizio viene definita tipo di servizio in WCF.

Il passaggio successivo consiste nell'associare un indirizzo e un'associazione a un tipo di servizio. Questa operazione viene in genere eseguita in un file di configurazione, modificando direttamente il file o usando un editor di configurazione fornito con WCF. Di seguito è riportato un esempio di file di configurazione.

<?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>

L'associazione specifica il set di protocolli per la comunicazione con l'applicazione. Nella tabella seguente sono elencate le associazioni fornite dal sistema che rappresentano le opzioni comuni.

Nome Scopo
BasicHttpBinding Interoperabilità con servizi Web e client che supportano i WS-BasicProfile 1.1 e Basic Security Profile 1.0.
WSHttpBinding Interoperabilità con servizi Web e client che supportano i protocolli WS-* su HTTP.
WSDualHttpBinding Comunicazione HTTP duplex, in base alla quale il ricevitore di un messaggio iniziale non risponde direttamente al mittente iniziale, ma può trasmettere qualsiasi numero di risposte in un periodo di tempo usando HTTP in conformità con i protocolli WS-*.
WSFederationBinding Comunicazione HTTP, in cui l'accesso alle risorse di un servizio può essere controllato in base alle credenziali rilasciate da un provider di credenziali identificato in modo esplicito.
NetTcpBinding Comunicazione sicura, affidabile e ad alte prestazioni tra le entità software WCF in una rete.
NetNamedPipeBinding Comunicazione sicura, affidabile e ad alte prestazioni tra entità software WCF nello stesso computer.
NetMsmqBinding Comunicazione tra entità software WCF tramite MSMQ.
MsmqIntegrationBinding Comunicazione tra un'entità software WCF e un'altra entità software tramite MSMQ.
NetPeerTcpBinding Comunicazione tra entità software WCF tramite la rete peer-to-peer di Windows.

L'associazione fornita dal sistema, BasicHttpBinding, incorpora il set di protocolli supportati da ASP.NET servizi Web.

Le associazioni personalizzate per le applicazioni WCF sono facilmente definite come raccolte delle classi di elementi di associazione usate da WCF per implementare singoli protocolli. È possibile scrivere nuovi elementi di associazione per rappresentare protocolli aggiuntivi.

Il comportamento interno dei tipi di servizio può essere modificato usando le proprietà di una famiglia di classi denominate comportamenti. In questo caso, la ServiceBehaviorAttribute classe viene usata per specificare che il tipo di servizio deve essere multithreading.

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

Alcuni comportamenti, ad esempio ServiceBehaviorAttribute, sono attributi. Altri, quelli con proprietà che gli amministratori desiderano impostare, possono essere modificati nella configurazione di un'applicazione.

Nei tipi di servizio di programmazione, l'uso frequente viene fatto della OperationContext classe . La proprietà statica Current fornisce l'accesso alle informazioni sul contesto in cui è in esecuzione un'operazione. OperationContext è simile alle HttpContext classi e ContextUtil .

Servizi di hosting

I servizi Web di ASP.NET vengono compilati in una libreria di classi assembly. Viene fornito un file denominato file del servizio con estensione asmx e contiene una @ WebService direttiva che identifica la classe che contiene il codice per il servizio e l'assembly in cui si trova.

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

Il file del servizio viene copiato in una radice dell'applicazione ASP.NET in Internet Information Services (IIS) e l'assembly viene copiato nella sottodirectory \bin della radice dell'applicazione. L'applicazione è quindi accessibile usando l'URL (Uniform Resource Locator) del file del servizio nella radice dell'applicazione.

I servizi WCF possono essere ospitati facilmente in IIS 5.1 o 6.0, il servizio di attivazione dei processi windows (WAS) fornito come parte di IIS 7.0 e in qualsiasi applicazione .NET. Per ospitare un servizio in IIS 5.1 o 6.0, il servizio deve usare HTTP come protocollo di trasporto delle comunicazioni.

Per ospitare un servizio in IIS 5.1, 6.0 o IN WAS, seguire questa procedura:

  1. Compilare il tipo di servizio in un assemblaggio della libreria di classi.

  2. Creare un file di servizio con estensione svc con una @ ServiceHost direttiva per identificare il tipo di servizio:

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

  3. Copiare il file del servizio in una directory virtuale e l'assembly nella sottodirectory \bin di questa.

  4. Copiare il file di configurazione nella directory virtuale e denominarlo Web.config.

L'applicazione è quindi accessibile usando l'URL del file del servizio nella radice dell'applicazione.

Per ospitare un servizio WCF all'interno di un'applicazione .NET, compilare il tipo di servizio in un assembly della libreria di classi a cui fa riferimento l'applicazione e programmare l'applicazione per ospitare il servizio usando la ServiceHost classe . Di seguito è riportato un esempio della programmazione di base necessaria:

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 questo esempio viene illustrato come vengono specificati gli indirizzi per uno o più protocolli di trasporto nella costruzione di un oggetto ServiceHost. Questi indirizzi vengono definiti indirizzi di base.

L'indirizzo fornito per qualsiasi endpoint di un servizio WCF è un indirizzo relativo a un indirizzo di base dell'host dell'endpoint. L'host può avere un indirizzo di base per ogni protocollo di trasporto di comunicazione. Nella configurazione di esempio nel file di configurazione precedente, l'oggetto BasicHttpBinding selezionato per l'endpoint usa HTTP come protocollo di trasporto, quindi l'indirizzo dell'endpoint, EchoService, è relativo all'indirizzo di base HTTP dell'host. Nel caso dell'host nell'esempio precedente, l'indirizzo di base HTTP è http://www.contoso.com:8000/. Per un servizio ospitato in IIS o WAS, l'indirizzo di base è l'URL del file del servizio del servizio.

Solo i servizi ospitati in IIS o WAS e configurati con HTTP come protocollo di trasporto esclusivamente, possono essere resi disponibili per l'uso dell'opzione modalità di compatibilità wcf ASP.NET. L'attivazione di tale opzione richiede i passaggi seguenti.

  1. Il programmatore deve aggiungere l'attributo AspNetCompatibilityRequirementsAttribute al tipo di servizio e specificare che ASP.NET modalità di compatibilità è consentita o obbligatoria.

    [System.ServiceModel.Activation.AspNetCompatibilityRequirements(
          RequirementsMode=AspNetCompatibilityRequirementsMode.Require)]
    public class DerivativesCalculatorServiceType: IDerivativesCalculator
    
  2. L'amministratore deve configurare l'applicazione per l'uso della modalità di compatibilità ASP.NET.

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

    Le applicazioni WCF possono anche essere configurate per l'uso di asmx come estensione per i file di servizio anziché con estensione svc.

    <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>
    

    Questa opzione consente di salvare l'utente dalla necessità di modificare i client configurati per l'uso degli URL dei file del servizio asmx durante la modifica di un servizio per l'uso di WCF.

Sviluppo di client

I client per ASP.NET servizi Web vengono generati usando lo strumento da riga di comando WSDL.exe, che fornisce l'URL del file asmx come input. Lo strumento corrispondente fornito da WCF è ServiceModel Metadata Utility Tool (Svcutil.exe). Genera un modulo di codice con la definizione del contratto di servizio e la definizione di una classe client WCF. Genera anche un file di configurazione con l'indirizzo e l'associazione del servizio.

Nella programmazione di un client di un servizio remoto è in genere consigliabile programmare in base a un modello asincrono. Il codice generato dallo strumento WSDL.exe prevede sempre, per impostazione predefinita, sia un modello sincrono che asincrono. Il codice generato dallo strumento utilità metadati ServiceModel (Svcutil.exe) può fornire entrambi i criteri. Fornisce per impostazione predefinita il modello sincrono. Se lo strumento viene eseguito con l'opzione /async , il codice generato fornisce il modello asincrono.

Non esiste alcuna garanzia che i nomi nelle classi client WCF generate dallo strumento di WSDL.exe ASP.NET, per impostazione predefinita, corrispondano ai nomi nelle classi client WCF generate dallo strumento Svcutil.exe. In particolare, i nomi delle proprietà delle classi che devono essere serializzate utilizzando XmlSerializer sono, per impostazione predefinita, dati il suffisso Property nel codice generato dallo strumento Svcutil.exe, cosa che non accade con lo strumento WSDL.exe.

Rappresentazione dei messaggi

Le intestazioni dei messaggi SOAP inviati e ricevuti da ASP.NET servizi Web possono essere personalizzate. Una classe deriva da SoapHeader per definire la struttura dell'intestazione e quindi SoapHeaderAttribute viene utilizzata per indicare la presenza dell'intestazione.

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;
     }
}

WCF fornisce gli attributi, MessageContractAttribute, MessageHeaderAttributee MessageBodyMemberAttribute per descrivere la struttura dei messaggi SOAP inviati e ricevuti da un servizio.

[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);
}

Questa sintassi restituisce una rappresentazione esplicita della struttura dei messaggi, mentre la struttura dei messaggi è implicita dal codice di un servizio Web ASP.NET. Inoltre, nella sintassi ASP.NET, le intestazioni del messaggio vengono rappresentate come proprietà del servizio, ad esempio la ProtocolHeader proprietà nell'esempio precedente, mentre nella sintassi WCF, sono rappresentate in modo più accurato come proprietà dei messaggi. WCF consente inoltre di aggiungere le intestazioni dei messaggi alla configurazione degli endpoint.

<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>

Questa opzione consente di evitare qualsiasi riferimento alle intestazioni del protocollo infrastrutturale nel codice per un client o un servizio: le intestazioni vengono aggiunte ai messaggi a causa della configurazione dell'endpoint.

Descrizione del servizio

L'emissione di una richiesta HTTP GET per il file asmx di un servizio Web ASP.NET con la query WSDL fa sì che ASP.NET generare WSDL per descrivere il servizio. Restituisce tale WSDL come risposta alla richiesta.

ASP.NET 2.0 ha consentito di verificare che un servizio sia conforme al profilo di base 1.1 dell'organizzazione web Services-Interoperability (WS-I) e di inserire un'attestazione che il servizio sia conforme al relativo WSDL. L'operazione viene effettuata utilizzando i parametri ConformsTo e EmitConformanceClaims dell'attributo WebServiceBindingAttribute.

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

È possibile personalizzare il WSDL generato ASP.NET per un servizio. Le personalizzazioni vengono effettuate creando una classe derivata di ServiceDescriptionFormatExtension per aggiungere elementi al file WSDL.

L'emissione di una richiesta HTTP GET con la query WSDL per il file con estensione svc di un servizio WCF con un endpoint HTTP ospitato in IIS 51, 6.0 o WAS fa sì che WCF risponda con WSDL per descrivere il servizio. L'emissione di una richiesta HTTP GET con la query WSDL all'indirizzo di base HTTP di un servizio ospitato in un'applicazione .NET ha lo stesso effetto se httpGetEnabled è impostato su true.

Tuttavia, WCF risponde anche alle richieste di tipo WS-MetadataExchange con WSDL generata per descrivere un servizio. I servizi Web di ASP.NET non dispongono del supporto predefinito per le richieste di WS-MetadataExchange.

Il linguaggio WSDL generato da WCF può essere ampiamente personalizzato. La ServiceMetadataBehavior classe fornisce alcune funzionalità per la personalizzazione di WSDL. Wcf può anche essere configurato per non generare WSDL, ma per usare un file WSDL statico in un determinato URL.

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

Gestione delle eccezioni

In ASP.NET servizi Web, le eccezioni non gestite vengono restituite ai client come errori SOAP. È anche possibile generare istanze della SoapException classe in modo esplicito e avere un maggiore controllo sul contenuto dell'errore SOAP che viene trasmesso al client.

Nei servizi WCF le eccezioni non gestite non vengono restituite ai client come errori SOAP per impedire che le informazioni riservate vengano esposte inavvertitamente tramite le eccezioni. Viene fornita un'impostazione di configurazione per avere eccezioni non gestite restituite ai client allo scopo di eseguire il debug.

Per restituire errori SOAP ai client, è possibile generare istanze del tipo generico, FaultException<TDetail>, usando il tipo di contratto dati come tipo generico. È anche possibile aggiungere FaultContractAttribute attributi alle operazioni per specificare gli errori che un'operazione potrebbe produrre.

[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);
}

In questo modo si ottengono i possibili errori annunciati nel WSDL per il servizio, consentendo ai programmatori client di prevedere quali errori possono derivare da un'operazione e scrivere le istruzioni catch appropriate.

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);
}

Gestione dello stato

La classe usata per implementare un servizio Web ASP.NET può essere derivata da WebService.

public class Service : WebService, IEcho
{

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

In tal caso, la classe può essere programmata per usare la proprietà Context della WebService classe base per accedere a un HttpContext oggetto . L'oggetto HttpContext può essere utilizzato per aggiornare e recuperare le informazioni sullo stato dell'applicazione usando la relativa proprietà Application e può essere utilizzato per aggiornare e recuperare le informazioni sullo stato della sessione utilizzando la relativa proprietà Session.

ASP.NET fornisce un notevole controllo sulla posizione in cui vengono effettivamente archiviate le informazioni sullo stato della sessione utilizzando la proprietà Session di HttpContext . Può essere archiviato in cookie, in un database, nella memoria del server corrente o nella memoria di un server designato. La scelta viene effettuata nel file di configurazione del servizio.

WCF fornisce oggetti estendibili per la gestione dello stato. Gli oggetti estendibili sono oggetti che implementano IExtensibleObject<T>. Gli oggetti estendibili più importanti sono ServiceHostBase e InstanceContext. ServiceHostBase consente di mantenere lo stato a cui possono accedere tutte le istanze di tutti i tipi di servizio nello stesso host, mentre InstanceContext consente di mantenere lo stato accessibile da qualsiasi codice in esecuzione all'interno della stessa istanza di un tipo di servizio.

In questo caso, il tipo di servizio TradingSystem, ha un ServiceBehaviorAttribute che specifica che tutte le chiamate dalla stessa istanza client WCF vengono indirizzate alla stessa istanza del tipo di servizio.

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

La classe DealData, , definisce lo stato accessibile da qualsiasi codice in esecuzione nella stessa istanza di un tipo di servizio.

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

Nel codice del tipo di servizio che implementa una delle operazioni del contratto di servizio, viene aggiunto un DealData oggetto stato allo stato dell'istanza corrente del tipo di servizio.

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

Tale oggetto di stato può quindi essere recuperato e modificato dal codice che implementa un'altra delle operazioni del contratto di servizio.

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

Mentre ASP.NET fornisce il controllo sulla posizione in cui vengono effettivamente archiviate le informazioni sullo stato nella HttpContext classe, WCF, almeno nella versione iniziale, non fornisce alcun controllo sulla posizione in cui vengono archiviati gli oggetti estendibili. Ciò costituisce il motivo migliore per selezionare la modalità di compatibilità ASP.NET per un servizio WCF. Se la gestione dello stato configurabile è imperativa, scegliere la modalità di compatibilità ASP.NET consente di usare le funzionalità della HttpContext classe esattamente come vengono usate in ASP.NET e anche di configurare la posizione in cui vengono archiviate le informazioni sullo stato gestite tramite la HttpContext classe .

Sicurezza

Le opzioni per proteggere ASP.NET servizi Web sono quelle per proteggere qualsiasi applicazione IIS. Poiché le applicazioni WCF possono essere ospitate non solo all'interno di IIS, ma anche all'interno di qualsiasi eseguibile .NET, le opzioni per la protezione delle applicazioni WCF devono essere rese indipendenti dalle funzionalità di IIS. Tuttavia, le funzionalità fornite per ASP.NET servizi Web sono disponibili anche per i servizi WCF in esecuzione in modalità di compatibilità ASP.NET.

Sicurezza: autenticazione

IIS offre funzionalità per il controllo dell'accesso alle applicazioni tramite cui è possibile selezionare l'accesso anonimo o una varietà di modalità di autenticazione: Autenticazione di Windows, Autenticazione digest, Autenticazione di base e Autenticazione di .NET Passport. L'opzione Autenticazione di Windows può essere usata per controllare l'accesso ai servizi Web di ASP.NET. Tuttavia, quando le applicazioni WCF sono ospitate in IIS, IIS deve essere configurato per consentire l'accesso anonimo all'applicazione, in modo che l'autenticazione possa essere gestita da WCF stessa, che supporta l'autenticazione di Windows tra le varie altre opzioni. Le altre opzioni predefinite includono token nome utente, certificati X.509, token SAML e scheda CardSpace, ma è anche possibile definire meccanismi di autenticazione personalizzati.

Sicurezza: impersonificazione

ASP.NET fornisce un elemento identity in base al quale è possibile creare un servizio Web di ASP.NET per rappresentare un determinato utente o le credenziali dell'utente fornite con la richiesta corrente. Tale elemento può essere usato per configurare l'impersonificazione nelle applicazioni WCF che funzionano in modalità di compatibilità ASP.NET.

Il sistema di configurazione WCF fornisce un proprio elemento di identità per designare un particolare utente da impersonare. Inoltre, i client e i servizi WCF possono essere configurati in modo indipendente per l'impersonificazione. I client possono essere configurati per rappresentare l'utente corrente quando trasmettono le richieste.

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

Le operazioni del servizio possono essere configurate per fingersi con le credenziali di qualsiasi utente fornite con la richiesta corrente.

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

Sicurezza: autorizzazione tramite elenchi di controllo di accesso

Gli elenchi di controllo di accesso (ACL) possono essere usati per limitare l'accesso ai file asmx. Tuttavia, gli ACL nei file di servizio WCF con estensione .svc vengono ignorati, tranne quando si è in modalità di compatibilità ASP.NET.

Sicurezza: autorizzazione basata su ruoli

L'opzione Autenticazione di Windows IIS può essere usata insieme all'elemento di autorizzazione fornito dal linguaggio di configurazione ASP.NET per facilitare l'autorizzazione basata sui ruoli per i servizi Web ASP.NET in base ai gruppi di Windows a cui vengono assegnati gli utenti. ASP.NET 2.0 ha introdotto un meccanismo di autorizzazione più generale basato sui ruoli: role provider.

I provider di ruoli sono classi che implementano tutte un'interfaccia di base per richiedere informazioni sui ruoli a cui è assegnato un utente, ma ogni provider di ruoli sa come recuperare tali informazioni da un'origine diversa. ASP.NET 2.0 fornisce un provider di ruoli in grado di recuperare le assegnazioni di ruolo da un database di Microsoft SQL Server e un altro che può recuperare le assegnazioni di ruolo da Gestione autorizzazioni di Windows Server 2003.

Il meccanismo del provider di ruoli può essere effettivamente usato indipendentemente da ASP.NET in qualsiasi applicazione .NET, inclusa un'applicazione WCF. La configurazione di esempio seguente per un'applicazione WCF mostra come l'uso di un provider di ruoli ASP.NET sia un'opzione selezionata tramite .ServiceAuthorizationBehavior

<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>

Sicurezza: autorizzazione basata sulle attestazioni

Una delle innovazioni più importanti di WCF è il supporto completo per autorizzare l'accesso alle risorse protette in base alle attestazioni. Le richieste consistono in un tipo, un diritto e un valore, come ad esempio una patente di guida. Esegue una serie di affermazioni sul portatore, tra cui la data di nascita del portatore. Il tipo di tale attestazione è la data di nascita, mentre il valore dell'attestazione è la data di nascita del conducente. Il diritto che un'attestazione conferisce al bearer specifica cosa può fare il bearer con il valore dell'attestazione. Nel caso del reclamo della data di nascita del conducente, il diritto è possesso: il conducente possiede tale data di nascita, ma non può, ad esempio, modificarlo. L'autorizzazione basata sulle attestazioni racchiude l'autorizzazione basata sui ruoli, perché i ruoli sono un tipo di attestazione.

L'autorizzazione basata sulle attestazioni viene eseguita confrontando un set di attestazioni con i requisiti di accesso dell'operazione e, a seconda del risultato di tale confronto, concedendo o negando l'accesso all'operazione. In WCF è possibile specificare una classe da usare per eseguire l'autorizzazione basata sulle attestazioni, assegnando nuovamente un valore alla ServiceAuthorizationManager proprietà di ServiceAuthorizationBehavior.

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

Le classi utilizzate per eseguire l'autorizzazione basata sulle dichiarazioni devono derivare da ServiceAuthorizationManager, che ha solo un metodo da sovrascrivere: AccessCheck(). WCF chiama tale metodo ogni volta che viene richiamata un'operazione del servizio e fornisce un oggetto OperationContext che ha le attestazioni per l'utente nella sua proprietà ServiceSecurityContext.AuthorizationContext. WCF esegue il lavoro di assemblaggio di attestazioni sull'utente da qualsiasi token di sicurezza fornito dall'utente per l'autenticazione, che lascia l'attività di valutare se tali attestazioni sono sufficienti per l'operazione in questione.

WCF compone automaticamente le dichiarazioni da qualsiasi tipo di token di sicurezza, un'innovazione estremamente significativa, perché rende il codice per l'autorizzazione basata sulle dichiarazioni completamente indipendente dal meccanismo di autenticazione. Al contrario, l'autorizzazione che usa elenchi di controllo di accesso o ruoli in ASP.NET è strettamente legata all'autenticazione di Windows.

Sicurezza: riservatezza

La riservatezza dei messaggi scambiati con ASP.NET servizi Web può essere garantita a livello di trasporto configurando l'applicazione all'interno di IIS per l'uso del protocollo HTTPS (Secure Hypertext Transfer Protocol). La stessa operazione può essere eseguita per le applicazioni WCF ospitate in IIS. Tuttavia, le applicazioni WCF ospitate all'esterno di IIS possono essere configurate anche per l'uso di un protocollo di trasporto sicuro. Più importante, le applicazioni WCF possono anche essere configurate per proteggere i messaggi prima di essere trasportati, usando il protocollo WS-Security. Proteggere solo il corpo di un messaggio utilizzando WS-Security consente di trasmettere in modo riservato attraverso intermediari prima di raggiungere la destinazione finale.

Globalizzazione

La lingua di configurazione ASP.NET consente di specificare le impostazioni cultura per i singoli servizi. WCF non supporta quella impostazione di configurazione, eccetto in modalità di compatibilità ASP.NET. Per localizzare un servizio WCF che non utilizza la modalità di compatibilità di ASP.NET, compilare i tipi di servizio in assembly specifici per cultura e avere endpoint specifici per ogni assembly culturale.

Vedere anche