Panoramica del livello del canale
Il livello canale fornisce un'astrazione del canale di trasporto, nonché i messaggi inviati sul canale. Include anche funzioni per la serializzazione dei tipi di dati C da e verso strutture SOAP. Il livello canale consente il controllo completo delle comunicazioni tramite messaggi costituiti da dati inviati o ricevuti e contenenti corpi e intestazioni e canali che astraggono protocolli di scambio di messaggi e forniscono proprietà per la personalizzazione delle impostazioni.
Message
Un messaggio è un oggetto che incapsula i dati di rete, in particolare i dati trasmessi o ricevuti in rete. La struttura dei messaggi è definita da SOAP, con un set discreto di intestazioni e un corpo del messaggio. Le intestazioni vengono inserite in un buffer di memoria e il corpo del messaggio viene letto o scritto usando un'API di flusso.
Anche se il modello di dati di un messaggio è sempre il modello di dati XML, il formato di collegamento effettivo è flessibile. Prima che un messaggio venga trasmesso, viene codificato usando una particolare codifica , ad esempio Text, Binary o MTOM. Per altre informazioni sulle codifiche, vedere WS_ENCODING .
Channel
Un canale è un oggetto usato per inviare e ricevere messaggi in una rete tra due o più endpoint.
I canali hanno associato dati che descrivono come risolvere il messaggio quando viene inviato. L'invio di un messaggio su un canale è come inserirlo in un chute: il canale include le informazioni in cui deve essere recato il messaggio e come ottenerlo.
I canali sono classificati in tipi di canale. Un tipo di canale specifica i messaggi di direzione che possono essere trasmessi. Il tipo di canale identifica anche se il canale è con sessione o senza sessione. Una sessione è definita come un modo astratto per correlare i messaggi tra due o più parti. Un esempio di canale con sessione è un canale TCP che usa la connessione TCP come implementazione concreta della sessione. Un esempio di canale senza sessione è UDP, che non dispone di un meccanismo di sessione sottostante. Anche se HTTP dispone di connessioni TCP sottostanti, questo fatto non viene esposto direttamente tramite questa API e pertanto HTTP viene considerato anche un canale senza sessione.
Anche se i tipi di canale descrivono le informazioni di direzione e sessione per un canale, non specificano la modalità di implementazione del canale. Quale protocollo deve usare il canale? Quanto è difficile che il canale tenti di recapitare il messaggio? Quale tipo di sicurezza viene usato? È singlecast o multicast? Queste impostazioni vengono definite "binding" del canale. L'associazione è costituita dai seguenti elementi:
- Un WS_CHANNEL_BINDING, che identifica il protocollo di trasferimento da usare (TCP, UDP, HTTP, NAMEDPIPE).
- Oggetto WS_edizione StandardCURITY_DESCRIPTION, che specifica come proteggere il canale.
- Set WS_CHANNEL_PROPERTYs, che specifica impostazioni facoltative aggiuntive. Vedere WS_CHANNEL_PROPERTY_ID per l'elenco delle proprietà.
Listener
Per iniziare a comunicare, il client crea un oggetto Channel. Ma in che modo il servizio ottiene l'oggetto Channel? A tale scopo, creare un listener. La creazione di un listener richiede le stesse informazioni di associazione necessarie per creare un canale. Dopo aver creato un listener, l'applicazione può accettare canali dal listener. Poiché l'applicazione può essere in ritardo nell'accettazione dei canali, i listener in genere mantengono una coda di canali pronti ad accettare (fino a una quota).
Avvio della comunicazione (client)
Per avviare la comunicazione sul client, usare la sequenza seguente.
WsCreateChannel
for each address being sent to
{
WsOpenChannel // open channel to address
// send and/or receive messages
WsCloseChannel // close channel
WsResetChannel? // reset if opening again
}
WsFreeChannel
Accettazione della comunicazione (server)
Per accettare le comunicazioni in ingresso nel server, usare la sequenza seguente.
WsCreateListener
WsOpenListener
for each channel being accepted (can be done in parallel)
{
WsCreateChannelForListener
for each accept
{
WsAcceptChannel // accept the channel
// send and/or receive messages
WsCloseChannel // close the channel
WsResetChannel? // reset if accepting again
}
WsFreeChannel
}
WsCloseListener
WsFreeListener
Invio di messaggi (client o server)
Per inviare messaggi, usare la sequenza seguente.
WsCreateMessageForChannel
for each message being sent
{
WsSendMessage // send message
WsResetMessage? // reset if sending another message
}
WsFreeMessage
La funzione WsSendMessage non consente lo streaming e presuppone che il corpo contenga un solo elemento. Per evitare questi vincoli, usare la sequenza seguente anziché WsSendMessage.
WsInitializeMessage // initialize message to WS_BLANK_MESSAGE
WsSetHeader // serialize action header into header buffer
WsAddressMessage? // optionally address message
for each application defined header
{
WsAddCustomHeader // serialize application-defined headers into header buffer
}
WsWriteMessageStart // write out the headers of the message
for each element of the body
{
WsWriteBody // serialize the element of the body
WsFlushBody? // optionally flush the body
}
WsWriteMessageEnd // write the end of the message
La funzione WsWriteBody usa la serializzazione per scrivere gli elementi del corpo. Per scrivere i dati direttamente nel writer XML, utilizzare la sequenza seguente anziché WsWriteBody.
WS_MESSAGE_PROPERTY_BODY_WRITER // get the writer used to write the body
WsWriteStartElement
// use the writer functions to write the body
WsWriteEndElement
// optionally flush the body
WsFlushBody?
La funzione WsAddCustomHeader usa la serializzazione per impostare le intestazioni sul buffer di intestazione del messaggio. Per utilizzare il writer XML per scrivere un'intestazione, utilizzare la sequenza seguente anziché WsAddCustomHeader.
WS_MESSAGE_PROPERTY_HEADER_BUFFER // get the header buffer
WsCreateWriter // create an xml writer
WsSetOutputToBuffer // specify output of writer should go to buffer
WsMoveWriter* // move to inside envelope header element
WsWriteStartElement // write application header start element
// use the writer functions to write the header
WsWriteEndElement // write application header end element
Ricezione di messaggi (client o server)
Per ricevere messaggi, usare la sequenza seguente.
WsCreateMessageForChannel
for each message being received
{
WsReceiveMessage // receive a message
WsGetHeader* // optionally access standard headers such as To or Action
WsResetMessage // reset if reading another message
}
WsFreeMessage
La funzione WsReceiveMessage non consente lo streaming e presuppone che il corpo contenga un solo elemento e che il tipo di messaggio (azione e schema del corpo) sia noto in anticipo. Per evitare questi vincoli, usare la sequenza seguente anziché WsReceiveMessage.
WsReadMessageStart // read all headers into header buffer
for each standard header
{
WsGetHeader // deserialize standard header such as To or Action
}
for each application defined header
{
WsGetCustomHeader // deserialize application defined header
}
for each element of the body
{
WsFillBody? // optionally fill the body
WsReadBody // deserialize element of body
}
WsReadMessageEnd // read end of message
La funzione WsReadBody usa la serializzazione per leggere gli elementi del corpo. Per leggere i dati direttamente dal lettore XML, usare la sequenza seguente anziché WsReadBody.
WS_MESSAGE_PROPERTY_BODY_READER // get the reader used to read the body
WsFillBody? // optionally fill the body
WsReadToStartElement // read up to the body element
WsReadStartElement // consume the start of the body element
// use the read functions to read the contents of the body element
WsReadEndElement // consume the end of the body element
Le funzioni WsGetCustomHeader usano la serializzazione per ottenere le intestazioni dal buffer di intestazione del messaggio. Per usare il lettore XML per leggere un'intestazione, utilizzare la sequenza seguente anziché WsGetCustomHeader.
WS_MESSAGE_PROPERTY_HEADER_BUFFER // get the header buffer
WsCreateReader // create an xml reader
WsSetInputToBuffer // specify input of reader should be buffer
WsMoveReader* // move to inside header element
while looking for header to read
{
WsReadToStartElement // see if the header matches the application header
if header matched
{
WsGetHeaderAttributes? // get the standard header attributes
WsReadStartElement // consume the start of the header element
// use the read functions to read the contents of the header element
WsReadEndElement // consume the end of the header element
}
else
{
WsSkipNode // skip the header element
}
}
Richiesta di risposta (client)
L'esecuzione di una richiesta-risposta sul client può essere eseguita con la sequenza seguente.
WsCreateMessageForChannel // create request message
WsCreateMessageForChannel // create reply message
for each request reply
{
WsRequestReply // send request, receive reply
WsResetMessage? // reset request message (if repeating)
WsResetMessage? // reset reply message (if repeating)
}
WsFreeMessage // free request message
WsFreeMessage // free reply message
La funzione WsRequestReply presuppone un singolo elemento per il corpo dei messaggi di richiesta e risposta e che il tipo di messaggio (azione e schema del corpo) sia noto in anticipo. Per evitare queste limitazioni, il messaggio di richiesta e risposta può essere inviato manualmente, come illustrato nella sequenza seguente. Questa sequenza corrisponde alla sequenza precedente per l'invio e la ricezione di un messaggio, tranne dove indicato.
WsInitializeMessage // initialize message to WS_BLANK_MESSAGE
WsSetHeader // serialize action header into header buffer
WsAddressMessage? // optionally address message
// the following block is specific to sending a request
{
generate a unique MessageID for request
WsSetHeader // set the message ID
}
for each application defined header
{
WsAddCustomHeader // serialize application-defined headers into header buffer
}
WsWriteMessageStart // write out the headers of the message
for each element of the body
{
WsWriteBody // serialize the element of the body
WsFlushBody? // optionally flush the body
}
WsWriteMessageEnd // write the end of the message
WsReadMessageStart // read all headers into header buffer
// the following is specific to receiving a reply
{
WsGetHeader // deserialize RelatesTo ID of reply
verify request MessageID is equal to RelatesTo ID
}
for each standard header
{
WsGetHeader // deserialize standard header such as To or Action
}
for each application defined header
{
WsGetCustomHeader // deserialize application defined header
}
for each element of the body
{
WsFillBody? // optionally fill the body
WsReadBody // deserialize element of body
}
WsReadMessageEnd // read end of message
Richiesta di risposta (server)
Per ricevere un messaggio di richiesta sul server, usare la stessa sequenza descritta nella sezione precedente sulla ricezione dei messaggi.
Per inviare una risposta o un messaggio di errore, usare la sequenza seguente.
WsCreateMessageForChannel
for each reply being sent
{
WsSendReplyMessage | WsSendFaultMessageForError // send reply or fault message
WsResetMessage? // reset if sending another message
}
WsFreeMessage
La funzione WsSendReplyMessage presuppone un singolo elemento nel corpo e non consente lo streaming. Per evitare queste limitazioni, usare la sequenza seguente. Si tratta della sequenza precedente per l'invio di un messaggio, ma usa WS_REPLY_MESSAGE anziché WS_BLANK_MESSAGE durante l'inizializzazione.
// the following block is specific to sending a reply
{
WsInitializeMessage // initialize message to WS_REPLY_MESSAGE
}
WsSetHeader // serialize action header into header buffer
WsAddressMessage? // optionally address message
for each application defined header
{
WsAddCustomHeader // serialize application-defined headers into header buffer
}
WsWriteMessageStart // write out the headers of the message
for each element of the body
{
WsWriteBody // serialize the element of the body
WsFlushBody? // optionally flush the body
}
WsWriteMessageEnd // write the end of the message
Modelli di scambio dei messaggi
Il WS_CHANNEL_TYPE determina il modello di scambio di messaggi possibile per un determinato canale. Il tipo supportato varia in base all'associazione, come indicato di seguito:
- WS_HTTP_CHANNEL_BINDING supporta WS_CHANNEL_TYPE_REQUEST nel client e WS_CHANNEL_TYPE_REPLY nel server.
- WS_TCP_CHANNEL_BINDING supporta WS_CHANNEL_TYPE_DUPLEX_edizione Standard SSION nel client e WS_CHANNEL_TYPE_DUPLEX_edizione Standard SSION nel server.
- WS_UDP_CHANNEL_BINDING supporta WS_CHANNEL_TYPE_DUPLEX nel client e WS_CHANNEL_TYPE_INPUT nel server.
- WS_NAMEDPIPE_CHANNEL_BINDING supporta WS_CHANNEL_TYPE_DUPLEX nel client e WS_CHANNEL_TYPE_INPUT nel server.
Cicli di messaggi
Per ogni modello di scambio di messaggi, è presente un "ciclo" specifico che può essere usato per inviare o ricevere messaggi. Il ciclo descrive l'ordine legale delle operazioni necessarie per inviare/ricevere più messaggi. I cicli sono descritti di seguito come produzioni grammaticali. Il termine "end" è una ricezione in cui viene restituito WS_S_END (vedere Valori restituiti di Servizi Web Windows), che indica che non sono disponibili altri messaggi nel canale. La produzione parallela specifica che per parallel(x & y) l'operazione x può essere eseguita simultaneamente con y.
Nel client vengono usati i cicli seguenti:
client-loop := client-request-loop | client-duplex-session-loop | client-duplex-loop
client-request-loop := open (send (receive | end))* close // WS_CHANNEL_TYPE_REQUEST
client-duplex-session-loop := open parallel(send* & receive*) parallel(send? & end*) close // WS_CHANNEL_TYPE_DUPLEX_SESSION
client-duplex-loop := open parallel(send & receive)* close // WS_CHANNEL_TYPE_DUPLEX
Nel server vengono usati i cicli seguenti:
server-loop: server-reply-loop | server-duplex-session-loop | server-duplex-loop
server-reply-loop := accept receive end* send? end* close // WS_CHANNEL_TYPE_REPLY
server-duplex-session-loop := accept parallel(send* & receive*) parallel(send* & end*) close // WS_CHANNEL_TYPE_DUPLEX_SESSION
server-input-loop := accept receive end* close // WS_CHANNEL_TYPE_INPUT
L'uso del WS_edizione StandardCURITY_CONTEXT_MESSAGE_edizione StandardCURITY_BINDING nel server richiede una ricezione corretta prima che l'invio sia consentito anche con un canale di tipo WS_CHANNEL_TYPE_DUPLEX_edizione Standard SSION. Dopo la prima ricezione. si applica il ciclo regolare.
Si noti che i canali di tipo WS_CHANNEL_TYPE_REQUEST e WS_CHANNEL_TYPE_REPLY possono essere usati per inviare e ricevere messaggi unidirezionale (nonché il modello standard request-reply). Questa operazione viene eseguita chiudendo il canale di risposta senza inviare una risposta. In questo caso, non verrà ricevuta alcuna risposta nel canale di richiesta. Il valore restituito WS_S_END Using the WS_edizione StandardCURITY_CONTEXT_MESSAGE_edizione StandardCURITY_BINDING sul server richiede una ricezione corretta prima che l'invio sia consentito anche con un canale di tipo WS_CHANNEL_TYPE_DUPLEX_edizione Standard SSION. Dopo la prima ricezione viene applicato il ciclo regolare.
verrà restituito, a indicare che non è disponibile alcun messaggio.
I cicli client o server possono essere eseguiti in parallelo tra loro usando più istanze del canale.
parallel-client: parallel(client-loop(channel1) & client-loop(channel2) & ...)
parallel-server: parallel(server-loop(channel1) & server-loop(channel2) & ...)
Filtro messaggi
Un canale server può filtrare i messaggi ricevuti non destinati all'applicazione, ad esempio messaggi che stabiliscono un contesto di sicurezza. In tal caso , WS_S_END verrà restituito da WsReadMessageStart e non saranno disponibili messaggi dell'applicazione su tale canale. Tuttavia, questo non segnala che il client ha intenzione di terminare la comunicazione con il server. Altri messaggi potrebbero essere disponibili in un altro canale. Vedere WsShutdownSessionChannel.
Annullamento
La funzione WsAbortChannel viene usata per annullare operazioni di I/O in sospeso per un canale. Questa API non attenderà il completamento delle operazioni di I/O. Per altre informazioni, vedere il diagramma dello stato WS_CHANNEL_STATE e la documentazione per WsAbortChannel.
L'API WsAbortListener viene usata per annullare le operazioni di I/O in sospeso per un listener. Questa API non attenderà il completamento delle operazioni di I/O. L'interruzione di un listener causerà anche l'interruzione di qualsiasi accettazione in sospeso. Per altre informazioni, vedere il diagramma dello stato WS_LISTENER_STATE e WsAbortListener.
TCP
Il WS_TCP_CHANNEL_BINDING supporta SOAP su TCP. La specifica SOAP su TCP si basa sul meccanismo di frame .NET.
La condivisione delle porte non è supportata in questa versione. Ogni listener aperto deve usare un numero di porta diverso.
UDP
Il WS_UDP_CHANNEL_BINDING supporta SOAP su UDP.
Esistono diverse limitazioni con l'associazione UDP:
- Non è disponibile alcun supporto per la sicurezza.
- I messaggi possono essere persi o duplicati.
- È supportata una sola codifica: WS_ENCODING_XML_UTF8.
- I messaggi sono fondamentalmente limitati a 64.000 e spesso hanno una maggiore probabilità di perdita se le dimensioni superano l'MTU della rete.
HTTP
Il WS_HTTP_CHANNEL_BINDING supporta SOAP su HTTP.
Per controllare le intestazioni specifiche HTTP nel client e nel server, vedere WS_HTTP_MESSAGE_MAPPING.
Per inviare e ricevere messaggi non SOAP nel server, usare WS_ENCODING_RAW per WS_CHANNEL_PROPERTY_ENCODING.
NAMEDPIPES
Il WS_NAMEDPIPE_CHANNEL_BINDING supporta SOAP tramite named pipe, consentendo la comunicazione con il servizio Windows Communication Foundation (WCF) tramite NetNamedPipeBinding.
Correlazione dei messaggi di richiesta/risposta
I messaggi di richiesta/risposta sono correlati in uno dei due modi seguenti:
- La correlazione viene eseguita usando il canale come meccanismo di correlazione. Ad esempio, quando si usa WS_ADDRESSING_VERSION_TRANSPORT e WS_HTTP_CHANNEL_BINDING la risposta per il messaggio di richiesta è correlata alla richiesta dal fatto che si tratta del corpo dell'entità della risposta HTTP.
- La correlazione viene eseguita usando le intestazioni MessageID e RelatesTo. Questo meccanismo viene usato con WS_ADDRESSING_VERSION_1_0 e WS_ADDRESSING_VERSION_0_9 (anche quando si usa WS_HTTP_CHANNEL_BINDING). In questo caso, il messaggio di richiesta include l'intestazione MessageID. Il messaggio di risposta include un'intestazione RelatesTo con il valore dell'intestazione MessageID della richiesta. L'intestazione RelatesTo consente al client di correlare una risposta con una richiesta inviata.
Le API del livello canale seguenti usano automaticamente i meccanismi di correlazione appropriati in base alla WS_ADDRESSING_VERSION del canale.
Se queste API non vengono usate, le intestazioni possono essere aggiunte e accessibili manualmente tramite WsSetHeader o WsGetHeader.
Canali e listener personalizzati
Se il set predefinito di associazioni di canale non soddisfa le esigenze dell'applicazione, è possibile definire un canale personalizzato e un'implementazione del listener specificando WS_CUSTOM_CHANNEL_BINDING durante la creazione del canale o del listener. L'implementazione effettiva del canale/listener viene specificata come set di callback tramite WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_CALLBACKS o WS_LISTENER_PROPERTY_CUSTOM_LISTENER_CALLBACKS proprietà. Dopo aver creato un canale o un listener personalizzato, il risultato è un oggetto WS_CHANNEL o WS_LISTENER che può essere usato con le API esistenti.
È anche possibile usare un canale e un listener personalizzati con proxy del servizio e host del servizio specificando il valore WS_CUSTOM_CHANNEL_BINDING nell'enumerazione WS_CHANNEL_BINDING e le proprietà WS_CHANNEL_PROPERTY_CUSTOM_CHANNEL_CALLBACKS e WS_LISTENER_PROPERTY_CUSTOM_LISTENER_CALLBACKS durante la creazione del proxy del servizio o dell'host del servizio.
Sicurezza
Il canale consente di limitare la quantità di memoria usata per vari aspetti delle operazioni tramite proprietà quali:
- WS_CHANNEL_PROPERTY_MAX_BUFFERED_MESSAGE_SIZE,
- WS_CHANNEL_PROPERTY_MAX_STREAMED_MESSAGE_SIZE,
- WS_CHANNEL_PROPERTY_MAX_STREAMED_START_SIZE,
- WS_CHANNEL_PROPERTY_MAX_HTTP_REQUEST_HEADERS_BUFFER_SIZE,
- WS_CHANNEL_PROPERTY_MAX_edizione StandardSSION_DICTIONARY_SIZE.
Queste proprietà hanno valori predefiniti che sono conservativi e sicuri per la maggior parte degli scenari. I valori predefiniti e le eventuali modifiche apportate devono essere valutati attentamente contro potenziali vettori di attacco che possono causare denial of service da parte di un utente remoto.
Il canale consente di impostare valori di timeout per vari aspetti delle operazioni tramite proprietà come:
- WS_CHANNEL_PROPERTY_CONNECT_TIMEOUT,
- WS_CHANNEL_PROPERTY_edizione StandardND_TIMEOUT,
- WS_CHANNEL_PROPERTY_RECEIVE_RESPONedizione Standard_TIMEOUT,
- WS_CHANNEL_PROPERTY_RECEIVE_TIMEOUT,
- WS_CHANNEL_PROPERTY_RESOLVE_TIMEOUT,
- WS_CHANNEL_PROPERTY_CLOedizione Standard_TIMEOUT.
Queste proprietà hanno valori predefiniti che sono conservativi e sicuri per la maggior parte degli scenari. L'aumento dei valori di timeout aumenta la quantità di tempo in cui una parte remota può contenere una risorsa locale attiva, ad esempio memoria, socket e thread che eseguono operazioni di I/O sincrone. Un'applicazione deve valutare i valori predefiniti e prestare attenzione quando aumenta un timeout perché può aprire potenziali vettori di attacco che possono causare denial of service da un computer remoto.
Alcune delle altre opzioni di configurazione e considerazioni sulla progettazione delle applicazioni che devono essere valutate attentamente quando si usa l'API del canale WWSAPI:
- Quando si usa il livello canale/listener, spetta all'applicazione creare e accettare canali sul lato server. Analogamente, spetta all'applicazione creare e aprire canali sul lato client. Un'applicazione deve inserire un limite superiore su queste operazioni perché ogni canale utilizza memoria e altre risorse limitate, ad esempio i socket. Un'applicazione deve prestare particolare attenzione quando si crea un canale in risposta a qualsiasi azione attivata da un'entità remota.
- Spetta all'applicazione scrivere la logica per creare canali e accettarli. Ogni canale utilizza risorse limitate, ad esempio memoria e socket. Un'applicazione deve avere un limite superiore sul numero di canali che è disposto ad accettare o una parte remota potrebbe stabilire molte connessioni, portando a OOM e quindi denial of service. Deve anche ricevere attivamente messaggi da tali connessioni usando un piccolo timeout. Se non vengono ricevuti messaggi, si verifica il timeout dell'operazione e la connessione deve essere rilasciata.
- Spetta a un'applicazione inviare una risposta o un errore interpretando le intestazioni Soap ReplyTo o FaultTo. La procedura di sicurezza consiste nell'rispettare solo un'intestazione ReplyTo o FaultTo "anonima", vale a dire che la connessione esistente (TCP, HTTP) o l'IP di origine (UDP) deve essere usata per inviare la risposta SOAP. Le applicazioni devono prestare particolare attenzione quando si creano risorse (ad esempio un canale) per rispondere a un indirizzo diverso, a meno che il messaggio non sia stato firmato da una parte che possa parlare per l'indirizzo a cui viene inviata la risposta.
- La convalida eseguita nel livello del canale non sostituisce l'integrità dei dati ottenuta tramite la sicurezza. Un'applicazione deve basarsi sulle funzionalità di sicurezza di WWSAPI per assicurarsi che comunichi con un'entità attendibile e deve anche basarsi sulla sicurezza per garantire l'integrità dei dati.
Analogamente, sono disponibili opzioni di configurazione dei messaggi e considerazioni sulla progettazione delle applicazioni che devono essere valutate attentamente quando si usa l'API messaggi WWSAPI:
- Le dimensioni dell'heap utilizzate per archiviare le intestazioni di un messaggio possono essere configurate usando la proprietà WS_MESSAGE_PROPERTY_HEAP_PROPERTIES. L'aumento di questo valore consente di utilizzare più memoria dalle intestazioni del messaggio, che può portare a OOM.
- L'utente dell'oggetto messaggio deve rendersi conto che le API di accesso all'intestazione sono O(n) rispetto al numero di intestazioni nel messaggio, poiché verificano la presenza di duplicati. Le progettazioni che richiedono molte intestazioni in un messaggio possono causare un utilizzo eccessivo della CPU.
- Il numero massimo di intestazioni in un messaggio può essere configurato usando la proprietà WS_MESSAGE_PROPERTY_MAX_PROCESedizione StandardD_HEADERS. Esiste anche un limite implicito in base alle dimensioni dell'heap del messaggio. L'aumento di entrambi questi valori consente la presenza di più intestazioni, che complica il tempo necessario per trovare un'intestazione (quando si usano le API di accesso all'intestazione).