Guida rapida alla risoluzione dei problemi di WCF
In questo argomento viene elencata una serie di problemi noti rilevati dai clienti durante lo sviluppo di client e servizi WCF. Se il problema rilevato non presente in questo elenco, si consiglia di configurare la traccia del servizio. In tal modo verrà generato un file di traccia che è possibile visualizzare con il visualizzatore dei file di traccia e verranno ricevute informazioni dettagliate sulle eccezioni che si possono verificare nel servizio. Per altre informazioni sulla configurazione della traccia, vedere Configuring Tracing. Per altre informazioni sul visualizzatore dei file di traccia, vedere Service Trace Viewer Tool (SvcTraceViewer.exe).
-
Errore HTTP 404.3 - La pagina richiesta non può essere servita a causa della configurazione estensioni. Se la pagina è uno script, aggiungere un gestore. Se il file deve essere scaricato, aggiungere una mappa MIME. Errore dettagliato InformationModule StaticFileModule.
Il servizio rifiuta nuovi client se sta interagendo già con 10 client. Cosa sta succedendo?
Quale è l'indirizzo di base? In che modo è correlato a un indirizzo dell'endpoint?
Dopo aver installato Windows 7 e IIS, quando si tenta di passare al servizio WCF viene visualizzato il seguente messaggio di errore HTTP 404.3 di file non trovato
Il messaggio di errore completo è:
Errore HTTP 404.3 - La pagina richiesta non può essere servita a causa della configurazione estensioni. Se la pagina è uno script, aggiungere un gestore. Se il file deve essere scaricato, aggiungere una mappa MIME. Errore dettagliato InformationModule StaticFileModule.
Questo messaggio di errore viene visualizzato quando l'"Attivazione HTTP di Windows Communication Foundation" non è impostata in modo esplicito nel Pannello di controllo. Per effettuare questa impostazione accedere al Pannello di controllo e fare clic su Programmi e funzionalità nell'angolo in basso a sinistra della finestra. Fare clic su Attivazione o disattivazione delle funzionalità Windows. Espandere Microsoft .NET Framework 3.5.1. e selezionare Windows Communication Foundation HTTP Activation.
A volte viene restituita un'eccezione MessageSecurityException alla seconda richiesta se il client è inattivo per un periodo di tempo dopo la prima richiesta. Cosa sta succedendo?
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 sicurezza. 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 sicurezza con stato. I token del contesto di sicurezza con stato consentono inoltre a una sessione protetta di restare attiva quando un server Web viene riciclato. Per altre informazioni sull'utilizzo di token del contesto di sicurezza con stato in una sessione protetta, vedere Procedura: Creare un token di contesto di sicurezza per una sessione protetta. In alternativa, è possibile disabilitare le sessioni protette. Quando si utilizza il binding <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 How to: Create a Custom Binding Using the SecurityBindingElement. Prima di applicare qualsiasi opzione, è necessario conoscere i requisiti di sicurezza dell'applicazione.
Il servizio rifiuta nuovi client se sta interagendo già con 10 client. Cosa sta succedendo?
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 e in seguito rifiuta le nuove connessioni client fino a quando una delle sessioni correnti non viene chiusa. È possibile supportare più client in vari modi. Se il servizio non richiede le sessioni, non utilizzare un'associazione con sessione. Per altre informazioni, vedere Uso delle sessioni. Un'altra opzione consiste nell'incrementare il limite di sessioni impostando il valore della proprietà MaxConcurrentSessions sul numero adatto alla circostanza.
È possibile caricare la configurazione del servizio da una posizione diversa 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. 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;
}
}
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 di SDK.
Per altri problemi possibili, vedere l'argomento degli esempi Esecuzione degli esempi di Windows Communication Foundation.
Se il client sta utilizzando le credenziali di Windows e l'eccezione è SecurityNegotiationException, configurare Kerberos come descritto di seguito.
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>
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"
Ospitare il servizio in Internet Information Services (IIS) che, per impostazione predefinita, utilizza l'account del nome dell'entità servizio (SPN).
Registrare un nuovo SPN nel dominio utilizzando SetSPN. È necessario essere un amministratore di dominio per poter eseguire questa operazione.
Per altre informazioni sul protocollo Kerberos, vedere Concetti di sicurezza usati in WCF e:
Quando si genera un'<eccezione> FaultException 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 altre 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 .
Sembra che le operazioni unidirezionali e request-reply vengano restituite approssimativamente alla stessa velocità quando la risposta non contiene dati. Come mai?
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 vengano restituite al client più rapidamente delle operazioni request-reply; ma qualsiasi condizione che rallenta l'invio dei dati in uscita sulla rete rallenta le operazioni unidirezionali e le operazioni request-reply. Per altre informazioni, vedere Servizi unidirezionali e Accesso ai servizi tramite un client WCF.
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 altre 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.
In seguito alla modifica del primo parametro di un'operazione di passaggio da lettere maiuscole a lettere minuscole, il client genera un'eccezione. Come mai?
I valori dei nomi di parametro nella firma dell'operazione fanno parte del contratto e supportano 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.
Utilizzando uno degli strumenti di traccia, viene generata un'eccezione EndpointNotFoundException. Qual è il problema?
Se si sta utilizzando uno 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="http://localhost:8000/MyServer/"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IMyContract"
behaviorConfiguration="MyClient"
contract="IMyContract"
name="WSHttpBinding_IMyContract">
</endpoint>
<behaviors>
<endpointBehaviors>
<behavior name="MyClient">
<clientVia viaUri="http://localhost:8001/MyServer/"/>
</behavior>
</endpointBehaviors>
</behaviors>
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.
Condivisione di una porta tra un endpoint servizio e un endpoint MEX utilizzando NetTcpBinding
Se si specifica l'indirizzo di base per un servizio come net.tcp://MioServer:8080/MioServizio e si aggiungono gli endpoint seguenti:
<services>
<service name="Microsoft.Samples.NetTcp.CalculatorService">
<endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
Se inoltre si modifica una delle impostazioni NetTcpBinding come illustrato nel frammento di configurazione seguente:
<bindings>
<netTcpBinding>
<binding closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="11" maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Transport">
<transport clientCredentialType="Windows" protectionLevel="EncryptAndSign"/>
</security>
</binding>
</netTcpBinding>
</bindings>
Verrà visualizzato un errore analogo al seguente: Eccezione non gestita: System.ServiceModel.AddressAlreadyInUseException: Esiste già un listener nell'endpoint IP 0.0.0.0:9000. Per risolvere il problema, specificare un URL completo con una porta diversa per l'endpoint MEX come illustrato nel frammento di configurazione seguente:
<services>
<service name="Microsoft.Samples.NetTcp.CalculatorService">
<endpoint address="calcsvc" binding ="netTcpBinding" contract="Microsoft.Samples.NetTcp.ICalculator"/>
<endpoint address="net.tcp://localhost:9001/servicemodelsamples/mex" binding="mexTcpBinding" contract="IMetadataExchange" />
</service>
</services>
Quando si chiama un'applicazione HTTP Web WCF da un'applicazione SOAP WCF il servizio restituisce l'errore 405 Metodo non consentito
La chiamata a un'applicazione HTTP Web WCF (un servizio che usa WebHttpBinding e WebHttpBehavior) da un servizio WCF può generare l'eccezione seguente: Unhandled Exception: System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: The remote server returned an unexpected response: (405) Method Not Allowed.
Questa eccezione si verifica perché WCF sovrascrive l'oggetto in uscita OperationContext con l'oggetto in ingresso OperationContext. Per risolvere questo problema, creare un oggetto OperationContextScope all'interno dell'operazione del servizio HTTP Web WCF. Ad esempio:
public string Echo(string input)
{
using (new OperationContextScope(this.InnerChannel))
{
return base.Channel.Echo(input);
}
}