Share via


Guida rapida alla risoluzione dei problemi di WCF

In questo argomento viene utilizzato un formato domanda-risposta per descrivere alcuni dei problemi più comuni, cosa è possibile fare per risolverli e dove trovare ulteriori informazioni sul problema.

Domande

Domanda: a volte viene restituita un'eccezione MessageSecurityException alla seconda richiesta se il client è inattivo per un periodo di tempo dopo la prima richiesta. Qual è il problema?

La seconda richiesta può non riuscire principalmente per due ragioni: (1) la sessione è scaduta o (2) il server Web che sta ospitando il servizio è stato riciclato. Nel primo caso, la sessione è valida fino al timeout del servizio. Quando il servizio non riceve una richiesta dal client entro il periodo di tempo specificato nell'associazione del servizio (ReceiveTimeout), il servizio termina la sessione di protezione. I messaggi client successivi determinano l'eccezione MessageSecurityException. Il client deve ristabilire una sessione protetta con il servizio per inviare altri messaggi o utilizzare un token del contesto di protezione con stato. I token del contesto di protezione con stato consentono inoltre a una sessione protetta di restare attiva quando un server Web viene riciclato. Per ulteriori informazioni sull'utilizzo di token del contesto di protezione con stato in una sessione protetta, vedere Procedura: creare un token di contesto di protezione con stato per una sessione protetta. In alternativa, è possibile disabilitare le sessioni protette. Quando si utilizza l'associazione WsHttpBinding, è possibile impostare la proprietà establishSecurityContext su false per disabilitare le sessioni protette. Per disabilitare le sessioni protette per altre associazioni, è necessario creare un'associazione personalizzata. Per informazioni dettagliate sulla creazione di un'associazione personalizzata, vedere Procedura: creare un'associazione personalizzata utilizzando SecurityBindingElement. Prima di applicare qualsiasi opzione, è necessario conoscere i requisiti di protezione dell'applicazione.

Domanda: il servizio rifiuta nuovi client se sta interagendo già con 10 client. Qual è il problema?

Per impostazione predefinita, i servizi possono gestire solo 10 sessioni simultanee. Pertanto, se le associazioni del servizio utilizzano sessioni, il servizio accetta nuove connessioni client fino a raggiungere quel numero, dopodichè rifiuta le nuove connessioni client fino a quando una delle sessioni correnti viene chiusa. È possibile supportare più client in vari modi. Se il servizio non richiede le sessioni, non utilizzare un'associazione con sessione. (Per ulteriori informazioni, vedere Utilizzo di sessioni.) Un'altra opzione consiste nell'incrementare il limite di sessioni impostando il valore della proprietà MaxConcurrentSessions sul numero adatto alla circostanza.

Domanda: è possibile caricare la configurazione del servizio da un luogo diverso dal file di configurazione dell'applicazione WCF?

È possibile, tuttavia è necessario creare una classe ServiceHost personalizzata che esegue l'override del metodo ApplyConfiguration. All'interno di tale metodo è possibile chiamare la base per caricare la prima configurazione (se si desidera caricare anche le informazioni di configurazione standard), ma si può anche sostituire completamente il sistema di caricamento della configurazione. Si noti che se si desidera caricare la configurazione da un file di configurazione diverso dal quello dell'applicazione, è necessario analizzare direttamente il file di configurazione e caricare la configurazione.

Nell'esempio di codice seguente viene illustrato come eseguire l'override del metodo ApplyConfiguration e configurare direttamente un endpoint.

public class MyServiceHost : ServiceHost
{
  public MyServiceHost(Type serviceType, params Uri[] baseAddresses)  
    : base(serviceType, baseAddresses)
  { Console.WriteLine("MyServiceHost Constructor"); }

  protected override void ApplyConfiguration()
  {
    string straddress = GetAddress();
    Uri address = new Uri(straddress);
    Binding binding = GetBinding();
    base.AddServiceEndpoint(typeof(IData), binding, address);
  }

  string GetAddress()
  { return "http://MyMachine:7777/MyEndpointAddress/"; }

  Binding GetBinding()
  {
    WSHttpBinding binding = new WSHttpBinding();
    binding.Security.Mode = SecurityMode.None;
    return binding;
  }
}

Domanda: il servizio e il client funzionano correttamente, ma quando il client è in un altro computer non funzionano più. Qual è il problema?

In base all'eccezione, i problemi possono essere diversi:

  • Potrebbe essere necessario modificare gli indirizzi dell'endpoint del client sul nome host anziché su "localhost".
  • Potrebbe essere necessario aprire la porta all'applicazione. Per informazioni dettagliate, vedere Firewall Instructions negli esempi SDK.
  • Per altri possibili problemi, vedere l'argomento degli esempi Running the Samples in a Workgroup and Across Machines.
  • Se il client sta utilizzando le credenziali di Windows e l'eccezione è SecurityNegotiationException, configurare Kerberos come descritto di seguito.
    1. Aggiungere le credenziali di identificazione all'elemento dell'endpoint nel file App.config del client:

      <endpoint 
        address="http://MyServer:8000/MyService/" 
        binding="wsHttpBinding" 
        bindingConfiguration="WSHttpBinding_IServiceExample" 
        contract="IServiceExample" 
        behaviorConfiguration="ClientCredBehavior" 
        name="WSHttpBinding_IServiceExample">
        <identity>
          <userPrincipalName value="name@corp.contoso.com"/>
        </identity>
      </endpoint>
      
    2. Eseguire il servizio indipendente con l'account System o NetworkService. È possibile eseguire questo comando per creare una finestra di comando con l'account System:

      at 12:36  /interactive "cmd.exe"
      
    3. Ospitare il servizio in Internet Information Services (IIS) che, per impostazione predefinita, utilizza l'account del nome dell'entità servizio (SPN).

    4. Registrare un nuovo SPN nel dominio utilizzando SetSPN. Si noti che è necessario essere un amministratore di dominio per poter eseguire questa operazione.

Per ulteriori informazioni sul protocollo Kerberos, vedere Concetti relativi alla protezione utilizzati in WCF e:

Domanda: quando si genera un'eccezione FaultException<Exception> in cui il tipo è un'eccezione, viene restituito sempre un tipo FaultException generale sul client e non il tipo generico. Qual è il problema?

È consigliabile creare un tipo di dati dell'errore personalizzato e dichiararlo come tipo di dettaglio nel contratto di errore. Ciò è necessario in quanto, se si utilizzano tipi di eccezione forniti dal sistema:

  • Viene creata una dipendenza dal tipo che rimuove uno dei maggiori punti di forza delle applicazioni orientate ai servizi.
  • Non è possibile dipendere dalla serializzazione delle eccezioni in modo standard. Alcuni casi, come SecurityException, potrebbero non essere affatto serializzabili.
  • Vengono esposti dettagli di implementazione interni ai client. Per ulteriori informazioni, vedere Specifica e gestione di errori in contratti e servizi.

Se si sta eseguendo il debug di un'applicazione, tuttavia, è possibile serializzare le informazioni sull'eccezione e restituirle al client utilizzando la classe ServiceDebugBehavior.

Domanda: sembra che le operazioni unidirezionali e request-reply vengano restituite approssimativamente alla stessa velocità quando la risposta non contiene dati. Qual è il problema?

Per operazione unidirezionale si intende che il contratto dell'operazione accetta un messaggio di input e non restituisce un messaggio di output. In WCF, tutte le chiamate del client vengono restituite quando i dati in uscita sono stati scritti nella rete oppure viene generata un'eccezione. Le operazioni unidirezionali funzionano nello stesso modo e possono generare un'eccezione se il servizio non viene trovato o possono bloccarsi se il servizio non è pronto ad accettare i dati dalla rete. In genere in WCF ciò comporta che le chiamate unidirezionali vengono restituite al client più rapidamente delle operazioni request-reply; ma qualsiasi condizione che rallenta l'invio dei dati in uscita sulla rete rallenta anche le operazioni unidirezionali e le operazioni request-reply. Per ulteriori informazioni, vedere Servizi unidirezionali e Accesso ai servizi tramite client.

Domanda: utilizzando un certificato X.509 con il servizio viene generata un'eccezione System.Security.Cryptography.CryptographicException. Qual è il problema?

Questa situazione in genere si verifica dopo aver modificato l'account utente utilizzato per eseguire il processo di lavoro IIS. Ad esempio, in Windows XP, se si modifica l'account utente predefinito con cui si esegue Aspnet_wp.exe da ASPNET in un account utente personalizzato, è possibile che si verifichi questo errore. Se si utilizza una chiave privata, il processo che la utilizza dovrà disporre delle autorizzazioni per accedere al file in cui è archiviata tale chiave.

In questo caso, è necessario assegnare i privilegi di accesso in lettura all'account del processo per il file che contiene la chiave privata. Ad esempio, se il processo di lavoro IIS è in esecuzione con l'account Bob, è necessario assegnare a Bob l'accesso in lettura al file che contiene la chiave privata.

Per ulteriori informazioni su come assegnare all'account utente corretto l'accesso al file che contiene la chiave privata per un certificato X.509 specifico, vedere Procedura: rendere accessibili a WCF i certificati X.509.

Domanda: in seguito alla modifica del primo parametro di un'operazione, passando da lettere in maiuscolo a lettere in minuscolo, il client genera un'eccezione. Qual è il problema?

Il valore dei nomi di parametro nella firma dell'operazione fa parte del contratto e supporta la distinzione tra maiuscole e minuscole. Utilizzare l'attributo System.ServiceModel.MessageParameterAttribute quando è necessario distinguere tra il nome del parametro locale e i metadati che descrivono l'operazione per le applicazioni client.

Domanda: utilizzando uno degli strumenti di traccia, viene generata un'eccezione EndpointNotFoundException. Qual è il problema?

Se si sta utilizzando un strumento di traccia diverso dal meccanismo di traccia WCF fornito dal sistema e si riceve un'eccezione EndpointNotFoundException che indica una mancata corrispondenza del filtro di indirizzi, è necessario utilizzare la classe ClientViaBehavior per indirizzare i messaggi all'utilità di traccia e fare in modo che l'utilità reindirizzi tali messaggi all'indirizzo del servizio. La classe ClientViaBehavior modifica l'intestazione di indirizzamento Via per specificare il successivo indirizzo di rete separatamente dal destinatario finale, indicato dall'intestazione di indirizzamento To. Durante questa modifica è importante tuttavia non modificare l'indirizzo dell'endpoint che viene utilizzato per stabilire il valore To.

Nell'esempio di codice seguente viene illustrato un file di configurazione client di esempio.

<endpoint 
  address=https://localhost:8000/MyServer/
  binding="wsHttpBinding"
  bindingConfiguration="WSHttpBinding_IMyContract"
  behaviorConfiguration="MyClient" 
  contract="IMyContract" 
  name="WSHttpBinding_IMyContract">
</endpoint>
<behaviors>
  <endpointBehaviors>
    <behavior name="MyClient">
      <clientVia viaUri="https://localhost:8001/MyServer/"/>
    </behavior>
  </endpointBehaviors>
</behaviors>

Domanda: quale è l'indirizzo di base? In che modo è correlato a un indirizzo dell'endpoint?

Un indirizzo di base è l'indirizzo radice per una classe ServiceHost. Per impostazione predefinita, se si aggiunge una classe ServiceMetadataBehavior alla configurazione del servizio, il linguaggio di descrizione dei servizi Web (WSDL, Web Services Description Language) per tutti gli endpoint che l'host pubblica viene recuperato dall'indirizzo di base HTTP, oltre che da qualsiasi indirizzo relativo fornito al comportamento dei metadati, più "?wsdl". Se si ha familiarità con ASP.NET e IIS, l'indirizzo di base è equivalente alla directory virtuale.

Domanda: come è possibile esporre più endpoint per un servizio?

È possibile eseguire questa operazione aggiungendo gli elementi <endpoint> all'elemento <service> in un file di configurazione dell'applicazione o eseguendo i passaggi equivalenti a livello di programmazione. Per ulteriori informazioni, vedere Specifica di un indirizzo endpoint, Procedura: creare un endpoint di servizio nella configurazione e Procedura: creare un endpoint del servizio nel codice.

Domanda: come è possibile determinare quali associazioni supportano comportamenti diversi?

Per ulteriori informazioni sulle associazioni fornite dal sistema e sulle funzionalità che supportano, vedere Associazioni fornite dal sistema.

Domanda: come è possibile configurare un'associazione standard con valori diversi per gli attributi?

Per ulteriori informazioni, vedere Configurazione di associazioni per i servizi Windows Communication Foundation.

Domanda: è necessario distribuire il servizio a un server HTTP se si desidera utilizzare HTTP come trasporto?

No. Tra le associazioni fornite dal sistema ve ne sono diverse che supportano i trasporti HTTP se utilizzati da qualsiasi tipo di applicazione host. Per ulteriori informazioni sulle associazioni fornite dal sistema e sulle funzionalità che supportano, vedere Associazioni fornite dal sistema.

Domanda: qual è il comportamento predefinito per un servizio che utilizza associazioni standard?

Dipende dall'associazione standard selezionata. In generale, il comportamento predefinito per le associazioni che utilizzano sessioni consiste nel creare una nuova istanza del servizio per ogni nuovo client e nell'indirizzare le chiamate successive da un particolare client all'istanza del servizio associata. Per ulteriori informazioni sulle associazioni fornite dal sistema e sulle funzionalità che supportano, vedere Associazioni fornite dal sistema.

Domanda: esiste un modo semplice per visualizzare il mapping delle funzionalità alle associazioni? Ad esempio, come è possibile stabilire quali associazioni supportano le transazioni, la protezione e così via?

È possibile eseguire queste operazioni. Vedere Associazioni fornite dal sistema.

Domanda: come è possibile passare tipi di dati personalizzati da un servizio a un client?

I tipi di dati passati tra due endpoint devono essere serializzabili, e il meccanismo di serializzazione più facile e interoperativo per i servizi consiste nell'utilizzare le classi DataContractAttribute e DataMemberAttribute. Per ulteriori informazioni su questo e altri meccanismi di serializzazione supportati, vedere Specifica del trasferimento di dati nei contratti di servizio.

Domanda: quando è necessario utilizzare un file di configurazione e quando è necessario eseguire la configurazione nel codice?

Poiché un file di configurazione dell'applicazione consente allo sviluppatore di delegare al distributore le decisioni sulla configurazione di runtime, è consigliabile utilizzare il codice del prodotto per la configurazione in tutti i casi in cui le decisioni non devono essere prese dai distributori. I distributori possono essere individui che installano programmi sui computer o amministratori aziendali che utilizzano criteri di gruppo aziendali per modificare i file di configurazione del computer e li bloccano per impedire modifiche locali. Per un esempio dell'ultimo caso, vedere Procedura: bloccare gli endpoint nell'organizzazione.

Domanda: cosa è necessario sapere per progettare correttamente un servizio?

Vedere Progettazione e implementazione di servizi.

Domanda: cosa sono tutti questi elementi nel codice generato dal client?

Per istruzioni sul codice generato dal client, vedere Informazioni sul codice client generato. Per ulteriori informazioni sull'architettura client, vedere Architettura client.

Domanda: perché è necessario chiamare il metodo Close sull'oggetto client WCF?

La chiamata del metodo Close sull'oggetto client WCF consente al client e al servizio di concludere normalmente la conversazione e riciclare le risorse associate. In aggiunta, se si stanno utilizzando sessioni, la chiamata al metodo Close può rappresentare il modo più rapido per determinare se la sessione ha generato errori dall'ultima chiamata, uno scenario che può essere rilevante per l'applicazione client. Per ulteriori informazioni, vedere Accesso ai servizi tramite client WCF e l'esempio Expected Exceptions.

Domanda: perché il servizio non funziona come previsto anche se il codice non contiene errori?

Se l'applicazione del servizio è configurata utilizzando un file di configurazione dell'applicazione, è necessario esaminare quel file per determinare se qualche elemento di configurazione o attributo sta alterando il comportamento di esecuzione in modo imprevisto. In particolare, il comportamento di runtime dipende in modo sostanziale dall'associazione che implementa il contratto in un endpoint. Verificare che l'associazione nel file di configurazione supporti le funzionalità desiderate e nel modo previsto.

Se il file di configurazione risulta corretto, è possibile continuare ad esaminare il comportamento di runtime dell'applicazione utilizzando le funzionalità di diagnostica come la registrazione e la traccia. Per ulteriori informazioni, vedere Amministrazione e diagnostica.

Domanda: quale è il miglior modo per comunicare a un client che si sono verificati problemi con il servizio?

Il modo migliore consiste nell'aggiungere all'operazione una classe FaultContractAttribute con un tipo di dati dell'errore serializzabile personalizzato. Quindi, quando l'operazione rileva una condizione di errore che può individuare, genera una nuova eccezione FaultException in cui il parametro di tipo è il tipo di errore serializzabile. Per ulteriori informazioni, vedere Specifica e gestione di errori in contratti e servizi.

Domanda: quali informazioni è giusto passare nuovamente al client?

Restituire solo le informazioni che i client del servizio devono conoscere. Lo sviluppatore del servizio deve fornire solo tali informazioni per minimizzare l'esposizione di dettagli di implementazione interni ai client non autorizzati. È consigliabile non restituire oggetti Exception negli errori SOAP. Per ulteriori informazioni, vedere Specifica e gestione di errori in contratti e servizi.

Domanda: in che modo l'applicazione client rileva che una connessione a un servizio è stata chiusa?

È possibile gestire gli eventi di cambiamento dello stato CommunicationObject del canale client; tuttavia, se si riceve una notifica della chiusura o dell'errore di un canale ciò dipende dall'implementazione del canale. Ad esempio, una classe NetTcpBinding notifica abbastanza rapidamente che il canale è stato chiuso o è in errore perché la durata della sessione è associata alla durata del socket sottostante.

Tuttavia, un'associazione con sessione progettata per proteggere l'applicazione contro i piccoli disturbi della rete, come la sessione fornita dalla classe ReliableSessionBindingElement, può non inviare la notifica per un periodo di tempo mentre tenta di ristabilire la sessione. Poiché questa è la situazione in esame, è consigliabile non tentare di rilevare direttamente la disconnessione.

Trattare invece la sessione come una conversazione. Se si apre il canale, effettuare diverse chiamate di operazioni e chiudere correttamente il canale, quindi sarà possibile presupporre che il canale non sia stato chiuso in modo imprevisto. Per ulteriori informazioni sui client e le sessioni, vedere Utilizzo di sessioni. Per ulteriori informazioni sulla gestione delle eccezioni relative al canale sul client, vedere Accesso ai servizi tramite client. Per informazioni sulla gestione delle eccezioni in generali, vedere Specifica e gestione di errori in contratti e servizi.

Domanda: come è possibile configurare un certificato Secure Sockets Layer per la protezione del servizio WCF?

Vedere Procedura: configurare una porta con un certificato SSL.

Domanda: come è possibile utilizzare i controlli messaggi per registrare o modificare il messaggio?

Vedere gli argomenti seguenti:

Domanda: come è possibile aggiungere un indirizzo dell'endpoint che contiene informazioni aggiuntive?

Se si desidera allegare indirizzi dell'endpoint complessi a livello di programmazione (ad esempio, se è necessario specificare a livello di programmazione una classe EndpointAddress che contiene un'intestazione o un'identità specifica), è necessario eseguire le operazioni seguenti, in cui relativeOrAbsoluteAddress è un URI assoluto:

// Do this:
ServiceEndpoint e = myServiceHost.AddServiceEndpoint(c,b,"relativeOrAbsoluteAddress");
e.Address = new EndpointAddress(e.Address.Uri, /*other info like headers */);

Domanda: tentando di compilare un esempio ospitato sul web, la generazione non viene eseguita in quanto il comando crea una directory, copia o elimina ha esito negativo. Perché ciò si verifica?

Durante la compilazione, alcuni esempi ospitati sul Web tentano di copiare i file binari compilati del servizio WCF nella cartella %SystemDrive%\inetpub\wwwroot\ServiceModelSamples. In realtà, questa operazione distribuisce il servizio in IIS. Se l'account nel quale è in esecuzione il prompt dei comandi SDK o Visual Studio non è autorizzato a modificare la cartella, la compilazione si arresterà. Per risolvere il problema, è possibile effettuare una delle seguenti operazioni

  • Concedere autorizzazioni di modifica per %SystemDrive%\inetpub\wwwroot per l'account con cui si stanno compilando gli esempi.
    o
  • Eseguire il prompt dei comandi SDK o Visual Studio come amministratore.

Vedere anche

Concetti

Debug degli errori di autenticazione di Windows