Estensione di dispatcher
I dispatcher sono responsabili dell'estrazione dei messaggi in arrivo dai canali sottostanti, della loro conversione in chiamate al metodo nel codice dell'applicazione e della restituzione dei risultati al chiamante. Le estensioni del dispatcher consentono di modificare questa elaborazione. È possibile implementare controlli di parametri e messaggi che controllano o modificano il contenuto dei messaggi o dei parametri. È possibile modificare la modalità in cui i messaggi vengono indirizzati alle operazioni o forniscono altre funzionalità.
In questo argomento viene illustrato come usare le classi DispatchRuntime e DispatchOperation in un'applicazione del servizio Windows Communication Foundation (WCF) per modificare il comportamento di esecuzione predefinito di un dispatcher o per intercettare o modificare messaggi, parametri o valori restituiti prima o dopo il loro invio o recupero dal livello del canale. Per altre informazioni sull'elaborazione dei messaggi di runtime client equivalente, vedere Estensione dei client. Per comprendere il ruolo svolto dai tipi IExtensibleObject<T> nell'accesso allo stato condiviso tra vari oggetti di personalizzazione del runtime, vedere Extensible Objects.
Dispatcher
Il livello del modello di servizi esegue la conversione tra il modello di programmazione dello sviluppatore e lo scambio di messaggi sottostante, comunemente denominato livello del canale. In WCF, i dispatcher di canale ed endpoint (rispettivamente ChannelDispatcher e EndpointDispatcher) sono i componenti del servizio responsabili dell'accettazione di nuovi canali, della ricezione di messaggi, della chiamata e dell'invio di operazioni e dell'elaborazione delle risposte. Gli oggetti dispatcher sono oggetti destinatario, ma anche le implementazioni del contratto di callback nei servizi duplex espongono oggetti dispatcher per ispezione, modifica o estensione.
Il dispatcher del canale (e la classe IChannelListener complementare) estrae i messaggi dal canale sottostante e li passa ai rispettivi dispatcher dell'endpoint. Ogni dispatcher dell'endpoint ha una classe DispatchRuntime che indirizza i messaggi alla classe DispatchOperation appropriata, responsabile della chiamata al metodo che implementa l'operazione. Durante il processo vengono richiamate varie classi di estensione facoltative e obbligatorie. In questo argomento viene illustrato come vengono assemblati questi pezzi e come è possibile modificare proprietà e inserirvi il proprio codice per estendere la funzionalità di base.
Le proprietà dispatcher e gli oggetti di personalizzazione modificati vengono inseriti usando oggetti comportamento di servizi, endpoint, contratti o operazioni. In questo argomento non viene descritto come usare i comportamenti. Per altre informazioni sui tipi usati per inserire modifiche del dispatcher, vedere Configurazione ed estensione del runtime con comportamenti.
Nel grafico seguente viene fornita una panoramica dettagliata degli elementi architettonici di un servizio.
Dispatcher del canale
Viene creato un oggetto ChannelDispatcher per associare una classe IChannelListener in un particolare URI (denominato URI di ascolto) a un'istanza di un servizio. Ogni oggetto ServiceHost può avere numerosi oggetti ChannelDispatcher, ognuno associato a un solo listener e URI di ascolto. All'arrivo di un messaggio ChannelDispatcher esegue una query su ognuno degli oggetti EndpointDispatcher associati per scoprire se l'endpoint può accettare il messaggio, quindi passa il messaggio all'endpoint che ne ha la possibilità.
Tutte le proprietà che controllano la durata e il comportamento di una sessione del canale sono disponibili per essere controllate o modificate sull'oggetto ChannelDispatcher. Sono inclusi gli inizializzatori di canale personalizzati, il listener del canale, l'host, l'oggetto InstanceContexte associato e così via.
Dispatcher dell'endpoint
L'oggetto EndpointDispatcher è responsabile dell'elaborazione dei messaggi da una classe ChannelDispatcher, quando l'indirizzo di destinazione di un messaggio corrisponde alla proprietà AddressFilter e l'azione del messaggio corrisponde alla proprietà ContractFilter. Se due oggetti EndpointDispatcher possono accettare un messaggio, il valore della proprietà FilterPriority determina l'endpoint con la priorità più elevata.
Usare EndpointDispatcher per acquisire i due principali punti di estensione del modello di servizi, ovvero le classi DispatchRuntime e DispatchOperation, utilizzabili per personalizzare l'elaborazione del dispatcher. La classe DispatchRuntime consente agli utenti di intercettare ed estendere il dispatcher nell'ambito del contratto, ovvero per tutti i messaggi del contratto. La classe DispatchOperation consente agli utenti di intercettare ed estendere il dispatcher nell'ambito di un'operazione, ovvero per tutti i messaggi in un'operazione.
Scenari
Esistono vari motivi per estendere il dispatcher:
Convalida di messaggi personalizzata. Gli utenti possono imporre che un messaggio sia valido per un certo schema. A questo scopo, è possibile implementare le interfacce degli intercettori di messaggi. Per un esempio, vedere Controllo messaggi.
Registrazione di messaggi personalizzata. Gli utenti possono controllare e registrare un set di messaggi dell'applicazione che passano attraverso un endpoint. Questa operazione può essere eseguita anche con le interfacce degli intercettori di messaggi.
Trasformazioni di messaggi personalizzate. Gli utenti possono applicare determinate trasformazioni al messaggio nel runtime (ad esempio per il controllo delle versioni). Anche in questo caso, l'operazione può essere eseguita con le interfacce degli intercettori di messaggi.
Modello di dati personalizzato. Gli utenti possono disporre di un modello di serializzazione dei dati diverso da quelli supportati per impostazione predefinita in WCF (ovvero oggetti System.Runtime.Serialization.DataContractSerializer, System.Xml.Serialization.XmlSerializer e messaggi non elaborati). A questo scopo, è possibile implementare le interfacce dei formattatori di messaggi. Per un esempio, vedere Formattatore dell'operazione e selettore di operazioni.
Convalida di parametri personalizzata. Gli utenti possono imporre che i parametri tipizzati siano validi (a differenza di XML). A questo scopo, è possibile usare le interfacce di controllo dei parametri.
Invio di operazioni personalizzato. Gli utenti possono implementare l'invio su un elemento diverso dall'azione, ad esempio, sull'elemento corpo o su una proprietà del messaggio personalizzata. A questo scopo, usare l'interfaccia IDispatchOperationSelector. Per un esempio, vedere Formattatore dell'operazione e selettore di operazioni.
Pool di oggetti. Gli utenti possono eseguire il pool delle istanze invece di allocare una nuova istanza per ogni chiamata. A questo scopo, usare le interfacce del provider di istanze. Per un esempio, vedere Pooling.
Leasing di istanza. Gli utenti possono implementare un modello di leasing per la durata dell'istanza, simile a quello di .NET Framework Remoting. A questo scopo, è possibile usare le interfacce di durata del contesto dell'istanza.
Gestione degli errori personalizzata. Gli utenti possono controllare come vengono elaborati gli errori locali e come vengono comunicati ai client. A questo scopo, usare le interfacce IErrorHandler.
Comportamenti di autorizzazione personalizzati. Gli utenti possono implementare il controllo di accesso personalizzato estendendo i pezzi di runtime Contratto o Operazione e aggiungendo controlli di sicurezza basati sui token presenti nel messaggio. L'operazione può essere eseguita con le interfacce degli intercettori di messaggi o di parametri. Per esempi, vedere Estendibilità della sicurezza.
Attenzione
Poiché la modifica di proprietà di sicurezza può compromettere la protezione delle applicazioni WCF, è consigliabile intraprendere modifiche relative alla protezione con attenzione e testarle accuratamente prima della distribuzione.
Validator del runtime WCF personalizzati. È possibile installare validator personalizzati che esaminano servizi, contratti e binding, per imporre criteri a livello di azienda in relazione ad applicazioni WCF. Ad esempio, vedere Procedura: Bloccare gli endpoint in Enterprise.
Utilizzo della classe DispatchRuntime
Usare la classe DispatchRuntime per modificare il comportamento predefinito di un servizio o di un singolo endpoint oppure per inserire oggetti che implementano modifiche personalizzate in uno o entrambi i processi del servizio (o i processi client nel caso di un client duplex) seguenti:
Trasformazione di messaggi in arrivo in oggetti e rilascio di tali oggetti come chiamate al metodo su un oggetto servizio.
Trasformazione di oggetti ricevuti dalla risposta a una chiamata a operazioni del servizio in messaggi in uscita.
DispatchRuntime consente di intercettare ed estendere il dispatcher del canale o dell'endpoint per tutti i messaggi di un particolare contratto, anche quando un messaggio non viene riconosciuto. Quando arriva un messaggio che non corrisponde ad alcun messaggio dichiarato nel contratto, viene inviato all'operazione restituita dalla proprietà UnhandledDispatchOperation. Per l'intercettazione o l'estensione in tutti i messaggi relativi a una particolare operazione, vedere la classe DispatchOperation.
Sono presenti quattro aree principali di estendibilità del dispatcher esposto dalla classe DispatchRuntime:
I componenti del canale usano le proprietà di DispatchRuntime e quelle del dispatcher del canale associato, restituito dalla proprietà ChannelDispatcher, per personalizzare la modalità usata dal dispatcher del canale per accettare e chiudere canali. In questa categoria sono incluse le proprietà ChannelInitializers e InputSessionShutdownHandlers.
I componenti dei messaggi vengono personalizzati per ogni messaggio elaborato. In questa categoria sono incluse le proprietà MessageInspectors, OperationSelector, Operations e ErrorHandlers.
I componenti dell'istanza personalizzano la creazione, la durata e l'eliminazione di istanze del tipo di servizio. Per altre informazioni sulle durate degli oggetti di servizio, vedere la proprietà InstanceContextMode. In questa categoria sono incluse le proprietà InstanceContextInitializers e InstanceProvider.
I componenti correlati alla protezione possono usare le proprietà seguenti:
SecurityAuditLogLocation indica dove vengono scritti gli eventi di controllo.
ImpersonateCallerForAllOperations controlla se il servizio tenta di eseguire una rappresentazione usando le credenziali fornite dal messaggio in ingresso.
MessageAuthenticationAuditLevel controlla se nel registro eventi specificato da SecurityAuditLogLocation vengono scritti eventi di autenticazione riuscita dei messaggi.
PrincipalPermissionMode controlla le modalità di impostazione della proprietà CurrentPrincipal.
ServiceAuthorizationAuditLevelspecifica le modalità di esecuzione del controllo degli eventi di autorizzazione.
SuppressAuditFailure specifica se sopprimere le eccezioni non critiche che si verificano durante il processo di registrazione.
In genere, gli oggetti di estensione personalizzati vengono assegnati a una proprietà DispatchRuntime o inseriti in una raccolta da un comportamento del servizio (un oggetto che implementa IServiceBehavior), un comportamento del contratto (un oggetto che implementa IContractBehavior) o un comportamento dell'endpoint (un oggetto che implementa IEndpointBehavior). L'oggetto del comportamento da installare viene quindi aggiunto alla raccolta appropriata di comportamenti a livello di programmazione o implementando un oggetto BehaviorExtensionElement personalizzato per consentire l'inserimento del comportamento usando un file di configurazione dell'applicazione.
I client duplex (client che implementano un contratto di callback specificato da un servizio duplex) hanno anche un oggetto DispatchRuntime a cui è possibile accedere usando la proprietà CallbackDispatchRuntime.
Utilizzo della classe DispatchOperation
La classe DispatchOperation è il luogo in cui è possibile eseguire modifiche del runtime ed è il punto di inserimento per estensioni personalizzate nell'ambito di una sola operazione del servizio. Per modificare il comportamento del runtime del servizio per tutti i messaggi di un contratto, usare la classe DispatchRuntime.
Installare modifiche di DispatchOperation usando un oggetto comportamento del servizio personalizzato.
Usare la proprietà Operations per individuare l'oggetto DispatchOperation che rappresenta un'operazione specifica del servizio.
Le proprietà seguenti controllano l'esecuzione del runtime a livello di operazione:
Le proprietà Action, ReplyAction, FaultContractInfos, IsOneWay, IsTerminating e Name ottengono i rispettivi valori dell'operazione.
TransactionAutoComplete e TransactionRequired specificano il comportamento della transazione.
Le proprietà ReleaseInstanceBeforeCall e ReleaseInstanceAfterCall controllano la durata dell'oggetto di servizio definito dall'utente relativo alla classe InstanceContext.
Le proprietà DeserializeRequest, SerializeReply e Formatter consentono di controllare esplicitamente la conversione dei messaggi in oggetti e viceversa.
La proprietà Impersonation specifica il livello di rappresentazione dell'operazione.
La proprietà CallContextInitializers inserisce estensioni del contesto di chiamata personalizzate per l'operazione.
La proprietà AutoDisposeParameters controlla quando vengono eliminati definitivamente gli oggetti parametro.
La proprietà Invoker consente di inserire un oggetto invoker personalizzato.
La proprietà ParameterInspectors consente di inserire un controllo del parametro personalizzato utilizzabile per controllare o modificare parametri e valori restituiti.