Accesso ai servizi tramite client

Le applicazioni client devono creare, configurare e usare oggetti client o canale WCF per comunicare con i servizi. Nell'argomento Panoramica del client WCF viene fornita una panoramica degli oggetti e dei passaggi coinvolti nella creazione e nell'uso di oggetti client e canale.

In questo argomento vengono fornite informazioni dettagliate su alcuni dei problemi relativi ad applicazioni client e oggetti client e canale, che possono essere utili a seconda dello scenario.

Panoramica

In questo argomento vengono descritti il comportamento e i problemi relativi a:

  • Durata di canali e sessioni.

  • Gestione delle eccezioni.

  • Problemi che causano blocchi.

  • Inizializzazione interattiva dei canali.

Durata di canali e sessioni

Le applicazioni WCF (Windows Communication Foundation) includono due categorie di canali, datagrammi e sessioni.

Si definisce datagramma un canale in cui tutti i messaggi non sono correlati. Con un canale di datagramma, l'eventuale esito negativo di un'operazione di input o di output non ha di norma alcun effetto sulla successiva operazione ed è possibile riutilizzare lo stesso canale. Ne consegue che i canali di datagramma non hanno in genere esito negativo.

I canali con sessione sono invece canali con una connessione all'altro endpoint. I messaggi in una sessione su uno dei lati vengono sempre correlati alla stessa sessione sull'altro lato. Inoltre, perché una sessione possa essere considerata riuscita, entrambi i partecipanti a essa devono concordare sul fatto che i requisiti della conversazione siano stati soddisfatti. In caso contrario, il canale con sessione può avere esito negativo.

Aprire i client in modo esplicito o implicito chiamando la prima operazione.

Nota

Tentare di rilevare esplicitamente i canali con sessione in errore non è in genere utile, poiché il momento in cui si riceve la notifica dipende dall'implementazione della sessione. Poiché, ad esempio, la classe System.ServiceModel.NetTcpBinding (con la sessione affidabile disattivata) fa emergere la sessione della connessione TCP, se si è in ascolto dell'evento ICommunicationObject.Faulted sul servizio o sul client, è probabile che si riceva una notifica immediata in caso di errore di rete. Le sessioni affidabili (stabilite da associazioni in cui la classe System.ServiceModel.Channels.ReliableSessionBindingElement è attivata) sono però progettate per isolare i servizi da piccoli errori di rete. Se la sessione può essere ristabilita entro un periodo di tempo ragionevole, la stessa associazione, configurata per sessioni affidabili, potrebbe non generare errori fino a quando l'interruzione non dura per un periodo di tempo più lungo.

La maggior parte delle associazioni fornite dal sistema (che espongono canali al livello di applicazione) usa sessioni per impostazione predefinita, diversamente dall'associazione System.ServiceModel.BasicHttpBinding. Per altre informazioni, vedere Uso delle sessioni.

Utilizzo corretto delle sessioni

Le sessioni offrono un modo per sapere se l'intero scambio di messaggi è completo e se entrambi i lati lo considerano riuscito. È consigliabile che un'applicazione chiamante apra il canale, lo utilizzi e lo chiuda all'interno di un unico blocco try. Se un canale di sessione è aperto, il metodo ICommunicationObject.Close viene chiamato una volta e la chiamata viene restituita correttamente, la sessione ha esito positivo. Per esito positivo si intende, in questo caso, che tutto il recapito garantisce che l'associazione specificata è stata soddisfatta e che l'altro lato non ha chiamato ICommunicationObject.Abort sul canale prima di chiamare Close.

Nella sezione seguente viene fornito un esempio di tale approccio client.

Gestione delle eccezioni

La gestione di eccezioni nelle applicazioni client è semplice. Se un canale viene aperto, usato e chiuso all'interno di un blocco try, la conversazione ha avuto esito positivo, a meno che non venga generata un'eccezione. In genere, se viene generata un'eccezione, la conversazione viene interrotta.

Nota

Non è consigliabile usare l'istruzione using (Using in Visual Basic). poiché la fine dell'istruzione using può causare eccezioni che possono mascherare altre eccezioni che potrebbe essere necessario conoscere. Per altre informazioni, vedere Usare Chiudi e Interrompi per rilasciare risorse client WCF.

Nell'esempio di codice seguente viene illustrato il modello client consigliato usando un blocco try/catch e non l'istruzione using.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Microsoft.WCF.Documentation;

public class Client
{
  public static void Main()
  {
    // Picks up configuration from the config file.
    SampleServiceClient wcfClient = new SampleServiceClient();
    try
    {
      // Making calls.
      Console.WriteLine("Enter the greeting to send: ");
      string greeting = Console.ReadLine();
      Console.WriteLine("The service responded: " + wcfClient.SampleMethod(greeting));

      Console.WriteLine("Press ENTER to exit:");
      Console.ReadLine();

      // Done with service.
      wcfClient.Close();
      Console.WriteLine("Done!");
    }
    catch (TimeoutException timeProblem)
    {
      Console.WriteLine("The service operation timed out. " + timeProblem.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException<GreetingFault> greetingFault)
    {
      Console.WriteLine(greetingFault.Detail.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (FaultException unknownFault)
    {
      Console.WriteLine("An unknown exception was received. " + unknownFault.Message);
      Console.ReadLine();
      wcfClient.Abort();
    }
    catch (CommunicationException commProblem)
    {
      Console.WriteLine("There was a communication problem. " + commProblem.Message + commProblem.StackTrace);
      Console.ReadLine();
      wcfClient.Abort();
    }
  }
}

Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports Microsoft.WCF.Documentation

Public Class Client
    Public Shared Sub Main()
        ' Picks up configuration from the config file.
        Dim wcfClient As New SampleServiceClient()
        Try
            ' Making calls.
            Console.WriteLine("Enter the greeting to send: ")
            Dim greeting As String = Console.ReadLine()
            Console.WriteLine("The service responded: " & wcfClient.SampleMethod(greeting))

            Console.WriteLine("Press ENTER to exit:")
            Console.ReadLine()

            ' Done with service. 
            wcfClient.Close()
            Console.WriteLine("Done!")
        Catch timeProblem As TimeoutException
            Console.WriteLine("The service operation timed out. " & timeProblem.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch greetingFault As FaultException(Of GreetingFault)
            Console.WriteLine(greetingFault.Detail.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch unknownFault As FaultException
            Console.WriteLine("An unknown exception was received. " & unknownFault.Message)
            Console.ReadLine()
            wcfClient.Abort()
        Catch commProblem As CommunicationException
            Console.WriteLine("There was a communication problem. " & commProblem.Message + commProblem.StackTrace)
            Console.ReadLine()
            wcfClient.Abort()
        End Try
    End Sub
End Class

Nota

La verifica del valore della proprietà ICommunicationObject.State è una race condition e non è consigliabile per determinare se riutilizzare o chiudere un canale.

I canali di datagramma non hanno mai esito negativo anche se si verificano eccezioni quando vengono chiusi. Inoltre, i client non duplex la cui autenticazione mediante conversazione protetta non riesce generano di norma un'eccezione System.ServiceModel.Security.MessageSecurityException. Tuttavia, se il client duplex che usa una conversazione protetta non viene autenticato, riceve un'eccezione System.TimeoutException.

Per informazioni più complete sull'uso delle informazioni sugli errori a livello di applicazione, vedere Specifica e gestione degli errori in Contratti e servizi. In Eccezioni previste vengono descritte le eccezioni previste e viene illustrato in che modo gestirle. Per altre informazioni su come gestire gli errori durante lo sviluppo di canali, vedere Gestione di eccezioni ed errori.

Blocco dei client e prestazioni

Quando un'applicazione chiama in modo sincrono un'operazione request-reply, il client si blocca fino a quando non viene ricevuto un valore restituito o non viene generata un'eccezione (ad esempio, System.TimeoutException). Si tratta di un comportamento simile al comportamento locale. Quando un'applicazione richiama in modo sincrono un'operazione su un oggetto client o un canale WCF, il client non viene restituito fino a quando il livello del canale non riesce a scrivere i dati nella rete o fino a quando non viene generata un'eccezione. Sebbene il modello di scambio di messaggi unidirezionale (specificato contrassegnando un'operazione con la proprietà OperationContractAttribute.IsOneWay impostata su true) possa aumentare la capacità di risposta di alcuni client, le operazioni unidirezionali possono anche creare blocchi, a seconda dell'associazione e dei messaggi già inviati. Le operazioni unidirezionali riguardano esclusivamente lo scambio di messaggi. Per altre informazioni, consultare Servizi unidirezionali.

I grandi blocchi di dati possono rallentare l'elaborazione dei client, indipendentemente dal modello di scambio di messaggi. Per informazioni su come gestire questi problemi, vedere Dati di grandi dimensioni e streaming.

Se l'applicazione deve eseguire altre operazioni durante il completamento di un'operazione, è consigliabile creare una coppia di metodi asincroni sull'interfaccia di contratto del servizio implementata dal client WCF. Il modo più semplice per eseguire questa operazione consiste nell'usare l'opzione /async sullo Strumento ServiceModel Metadata Utility (Svcutil.exe). Per un esempio, vedere Procedura: Chiamare operazioni del servizio in modo asincrono.

Per altre informazioni sull'aumento delle prestazioni del client, vedere Applicazioni client di livello intermedio.

Abilitazione dell'utente alla selezione dinamica di credenziali

L'interfaccia IInteractiveChannelInitializer consente alle applicazioni di visualizzare un'interfaccia utente che consente all'utente di scegliere le credenziali con cui viene creato un canale prima dell'avvio dei timer di timeout.

Gli sviluppatori di applicazioni possono usare un'interfaccia IInteractiveChannelInitializer inserita in due modi. L'applicazione client può chiamare ClientBase<TChannel>.DisplayInitializationUI o IClientChannel.DisplayInitializationUI (o una versione asincrona) prima di aprire il canale (l'approccio esplicito) o chiamare la prima operazione (approccio implicito).

Se si usa l'approccio implicito, l'applicazione deve chiamare la prima operazione su un'estensione ClientBase<TChannel> o IClientChannel. Se chiama un elemento diverso dalla prima operazione, viene generata un'eccezione.

Se si usa l'approccio esplicito, l'applicazione deve eseguire i passaggi seguenti nell'ordine rappresentato:

  1. Chiamare ClientBase<TChannel>.DisplayInitializationUI o IClientChannel.DisplayInitializationUI (o una versione asincrona).

  2. Quando gli inizializzatori restituiscono un valore, chiamare il metodo Open sull'oggetto IClientChannel o sull'oggetto IClientChannel restituito dalla proprietà ClientBase<TChannel>.InnerChannel.

  3. Chiamare le operazioni.

È consigliabile che le applicazioni di alta qualità controllino il processo dell'interfaccia utente adottando l'approccio esplicito.

Le applicazioni che usano l'approccio implicito richiamano gli inizializzatori dell'interfaccia utente, ma se l'utente dell'applicazione non risponde entro il periodo di timeout di invio dell'associazione, viene generata un'eccezione quando viene restituita l'interfaccia utente.

Vedi anche