Condividi tramite


Risoluzione dei problemi relativi alla correlazione

La correlazione viene utilizzata per correlare i messaggi del servizio flusso di lavoro l'uno all'altro e all'istanza del flusso di lavoro corretta, ma se non viene configurata correttamente, i messaggi non verranno ricevuti e le applicazioni non funzioneranno in modo appropriato. In questo argomento viene fornita una panoramica dei metodi che consentono di risolvere i problemi relativi alla correlazione e vengono inoltre descritti alcuni dei problemi comuni che possono verificarsi durante l'utilizzo della correlazione.

Gestire l'evento UnknownMessageReceived

L'evento UnknownMessageReceived si verifica quando un messaggio sconosciuto viene ricevuto da un servizio, inclusi i messaggi che non possono essere correlati a un'istanza esistente. Per i servizi indipendenti, questo evento può essere gestito nell'applicazione host.

host.UnknownMessageReceived += delegate(object sender, UnknownMessageReceivedEventArgs e)
{
    Console.WriteLine("Unknown Message Received:");
    Console.WriteLine(e.Message);
};

Per i servizi ospitati sul Web, questo evento può essere gestito derivando una classe da WorkflowServiceHostFactory ed eseguendo l'override del metodo CreateWorkflowServiceHost.

class CustomFactory : WorkflowServiceHostFactory
{
    protected override WorkflowServiceHost CreateWorkflowServiceHost(Activity activity, Uri[] baseAddresses)
    {
        // Create the WorkflowServiceHost.
        WorkflowServiceHost host = new WorkflowServiceHost(activity, baseAddresses);

        // Handle the UnknownMessageReceived event.
        host.UnknownMessageReceived += delegate(object sender, UnknownMessageReceivedEventArgs e)
        {
            Console.WriteLine("Unknown Message Received:");
            Console.WriteLine(e.Message);
        };

        return host;
    }
}

Questo oggetto WorkflowServiceHostFactory personalizzato può essere quindi specificato nel file svc per il servizio.

<% @ServiceHost Language="C#" Service="OrderServiceWorkflow" Factory="CustomFactory" %>

Il richiamo di questo gestore consente di recuperare il messaggio tramite la proprietà Message di UnknownMessageReceivedEventArgs e sarà simile al messaggio seguente:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:8080/OrderService</To>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService/AddItem</Action>
  </s:Header>
  <s:Body>
    <AddItem xmlns="http://tempuri.org/">
      <Item>Books</Item>
    </AddItem>
  </s:Body>
</s:Envelope>

L'ispezione dei messaggi inviati al gestore UnknownMessageReceived può fornire indicazioni sui motivi della mancata correlazione del messaggio a un'istanza del servizio flusso di lavoro.

Utilizzare il rilevamento per monitorare lo stato di avanzamento del flusso di lavoro

Il rilevamento consente di monitorare lo stato di avanzamento del flusso di lavoro. Per impostazione predefinita, vengono generati record di rilevamento per eventi del ciclo di vita di flusso del lavoro, eventi del ciclo di vita delle attività, propagazione degli errori e ripresa dei segnalibri. Record di rilevamento personalizzati possono inoltre essere generati da attività personalizzate. Durante la risoluzione dei problemi relativi alla correlazione, i record di rilevamento delle attività, di ripresa dei segnalibri e di propagazione degli errori costituiscono gli elementi più utili. I record di rilevamento delle attività possono essere utilizzati per determinare lo stato di avanzamento corrente del flusso di lavoro e consentono di identificare l'attività di messaggistica attualmente in attesa dei messaggi. I record di ripresa dei segnalibri sono utili perché indicano la ricezione di un messaggio da parte del flusso di lavoro, mentre i record di propagazione degli errori rendono disponibile un record degli errori presenti nel flusso di lavoro. Per abilitare il rilevamento, specificare l'oggetto TrackingParticipant desiderato nella proprietà WorkflowExtensions di WorkflowServiceHost. Nell'esempio seguente, l'oggetto ConsoleTrackingParticipant (dall'esempio di rilevamento personalizzato ) è configurato usando il profilo di rilevamento predefinito.

host.WorkflowExtensions.Add(new ConsoleTrackingParticipant());

Un partecipante del rilevamento, quale ConsoleTrackingParticipant, è utile per i servizi flusso di lavoro indipendenti che dispongono di una finestra della console. Per un servizio ospitato dal Web, un partecipante di rilevamento che registra le informazioni di rilevamento in un archivio durevole deve essere usato, ad esempio il partecipante predefinito EtwTrackingParticipanto un partecipante di rilevamento personalizzato che registra le informazioni in un file.

Per altre informazioni sul rilevamento e sulla configurazione del rilevamento per un servizio flusso di lavoro ospitato dal Web, vedere Rilevamento del flusso di lavoro e traccia, Configurazione del rilevamento per un flusso di lavoro e esempi di rilevamento [esempi di WF].

Utilizzare la funzionalità di traccia di WCF

La funzionalità di traccia di WCF consente di tracciare il flusso di messaggi da e verso un servizio flusso di lavoro. Queste informazioni di traccia sono utili per risolvere i problemi relativi alla correlazione, in particolare per la correlazione basata sul contenuto. Per abilitare la traccia, specificare i listener di traccia desiderati nella sezione system.diagnostics del file web.config se il servizio flusso di lavoro è ospitato sul Web oppure nel file app.config se il servizio flusso di lavoro è indipendente. Per includere il contenuto dei messaggi nel file di traccia, specificare true per logEntireMessage nell'elemento messageLogging nella sezione diagnostics di system.serviceModel. Nell'esempio seguente le informazioni di analisi, incluso il contenuto dei messaggi, sono configurate in modo da essere scritte in un file denominato service.svclog.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel" switchValue="Information" propagateActivity="true">
        <listeners>
          <add name="corr"/>
        </listeners>
      </source>
      <source name="System.ServiceModel.MessageLogging">
        <listeners>
          <add name="corr"/>
        </listeners>
      </source>
    </sources>

    <sharedListeners>
      <add name="corr" type="System.Diagnostics.XmlWriterTraceListener" initializeData="c:\logs\service.svclog">
      </add>
    </sharedListeners>
  </system.diagnostics>

  <system.serviceModel>
    <diagnostics>
      <messageLogging logEntireMessage="true" logMalformedMessages="false"
         logMessagesAtServiceLevel="false" logMessagesAtTransportLevel="true" maxSizeOfMessageToLog="2147483647">
      </messageLogging>
    </diagnostics>
  </system.serviceModel>
</configuration>

Per visualizzare le informazioni di traccia contenute in service.svclog, viene usato lo strumento Visualizzatore traccia del servizio (SvcTraceViewer.exe). Questa soluzione è particolarmente utile per risolvere i problemi relativi alla correlazione basata sul contenuto, in quanto consente di visualizzare il contenuto del messaggio e di vedere esattamente ciò che viene passato, nonché di determinarne la corrispondenza a CorrelationQuery per la correlazione basata sul contenuto. Per altre informazioni sulla traccia WCF, vedere Strumento visualizzatore traccia del servizio (SvcTraceViewer.exe),Configurazione della traccia e Uso della traccia per risolvere i problemi dell'applicazione.

Problemi comuni relativi alla correlazione di scambio del contesto

Per determinati tipi di correlazione, è necessario che venga associato un tipo specifico di associazione affinché la correlazione funzioni correttamente. Alcuni esempi includono la correlazione request/reply che richiede un'associazione bidirezionale, quale BasicHttpBinding, e la correlazione di scambio del contesto per la quale è necessaria un'associazione basata sul contesto, quale BasicHttpContextBinding. La maggior parte delle associazioni supporta operazioni bidirezionali, pertanto questo non rappresenta un problema comune per la correlazione request/reply, mentre è disponibile solo un numero limitato di associazioni basate sul contesto, tra cui BasicHttpContextBinding, WSHttpContextBinding e NetTcpContextBinding. Se non viene utilizzata una di queste associazioni, la chiamata iniziale a un servizio flusso di lavoro avrà esito positivo, ma le chiamate successive non riusciranno generando l'oggetto FaultException.

There is no context attached to the incoming message for the service
and the current operation is not marked with "CanCreateInstance = true".
In order to communicate with this service check whether the incoming binding
supports the context protocol and has a valid context initialized.

Le informazioni sul contesto utilizzate per la correlazione del contesto possono essere restituite da SendReply all'attività Receive che inizializza la correlazione del contesto in caso di utilizzo di un'operazione bidirezionale oppure essere specificate dal chiamante se l'operazione è unidirezionale. Se il contesto non viene inviato dal chiamante o non viene restituito dal servizio flusso di lavoro, verrà restituito lo stesso oggetto FaultException descritto in precedenza quando viene richiamata un'operazione successiva.

Problemi comuni relativi alla correlazione request/reply

La correlazione request-reply viene usata con una coppia per implementare un'operazione bidirezionale in un servizio flusso di lavoro e con una/ReceiveReplySendcoppia che richiama un'operazione bidirezionale in un altro servizio Web.Receive/SendReply Quando si richiama un'operazione bidirezionale in un servizio WCF, il servizio può essere un servizio WCF basato su codice imperativo tradizionale o può essere un servizio flusso di lavoro. Per utilizzare la correlazione request/reply, è necessario utilizzare un'associazione bidirezionale, ad esempio BasicHttpBinding, e che le operazioni siano bidirezionali.

Se il servizio flusso di lavoro ha operazioni bidirezionali in parallelo o sovrapposte ReceiveSendReplySend//ReceiveReply o coppie, la gestione implicita dell'handle di correlazione fornita da WorkflowServiceHost potrebbe non essere sufficiente, soprattutto negli scenari di stress elevato e i messaggi potrebbero non essere indirizzati correttamente. Per evitare che si verifichi questo problema, è consigliabile specificare sempre in modo esplicito un CorrelationHandle quando si utilizza la correlazione request/reply. Quando si usano i modelli SendAndReceiveReply e ReceiveAndSendReply dalla sezione Messaggistica della casella degli strumenti nella finestra di progettazione del flusso di lavoro, viene CorrelationHandle configurato in modo esplicito per impostazione predefinita. Durante la compilazione di un flusso di lavoro tramite codice, l'oggetto CorrelationHandle viene specificato nella proprietà CorrelationInitializers della prima attività nella coppia. Nell'esempio seguente un'attività Receive viene configurata con una proprietà CorrelationHandle esplicita specificata in RequestReplyCorrelationInitializer.

Variable<CorrelationHandle> RRHandle = new Variable<CorrelationHandle>();

Receive StartOrder = new Receive
{
    CanCreateInstance = true,
    ServiceContractName = OrderContractName,
    OperationName = "StartOrder",
    CorrelationInitializers =
    {
        new RequestReplyCorrelationInitializer
        {
            CorrelationHandle = RRHandle
        }
    }
};

SendReply ReplyToStartOrder = new SendReply
{
    Request = StartOrder,
    Content = ... // Contains the return value, if any.
};

// Construct a workflow using StartOrder and ReplyToStartOrder.

La persistenza non è consentita tra una coppia o una ReceiveReceiveReply/SendReplySend/coppia. Viene creata un'area di non persistenza che dura fino a quando non vengono completate entrambe le attività. Se un'attività, ad esempio un'attività di ritardo si trova in quest'area di non persistenza e determina che il flusso di lavoro diventi inattivo, tale flusso di lavoro non verrà conservato anche se l'host è configurato per rendere persistenti i flussi di lavoro quando diventano inattivi. Se un'attività, ad esempio un'attività Persist tenta di eseguire la persistenza in modo esplicito nell'area di non persistenza, viene generata un'eccezione irreversibile, il flusso di lavoro viene interrotto e al chiamante viene restituita un'eccezione FaultException. Il messaggio di eccezione irreversibile è "System.InvalidOperationException: blocchi di non persistenza non in grado di contenere le attività Persist". Questa eccezione non viene restituita al chiamante ma può essere osservata se il rilevamento è abilitato. Il messaggio dell'eccezione FaultException restituita al chiamante è "WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' è stata completata. Impossibile eseguire l'operazione".

Per altre informazioni sulla correlazione di richiesta-risposta, vedere Request-Reply.

Problemi comuni relativi alla correlazione di contenuto

La correlazione basata sul contenuto viene utilizzata quando un servizio flusso di lavoro riceve più messaggi e una parte dei dati inclusi nei messaggi scambiati identifica l'istanza desiderata. La correlazione basata sul contenuto utilizza questi dati nel messaggio, ad esempio un numero cliente o un ID dell'ordine, per indirizzare messaggi all'istanza del flusso di lavoro corretta. Contenuto della sezione vengono descritti alcuni problemi comuni che possono verificarsi durante l'utilizzo della correlazione basata sul contenuto.

Assicurarsi che i dati di identificazione siano univoci

Per i dati usati per l'identificazione dell'istanza viene generato un hash in una chiave di correlazione. È necessario verificare che i dati utilizzati per la correlazione siano univoci. In caso contrario, potrebbero verificarsi conflitti nella chiave con hash ed è possibile che i messaggi vengano indirizzati in modo errato. Una correlazione basata esclusivamente su un nome di cliente può ad esempio generare un conflitto, poiché possono esistere più clienti con lo stesso nome. Non utilizzare i due punti (:) come parte dei dati utilizzati per correlare il messaggio, in quanto vengono già utilizzati per delimitare il valore e la chiave della query del messaggio per formattare la stringa per la quale verrà generato un hash. Se si utilizza la persistenza, verificare che i dati di identificazione correnti non siano stati utilizzati da un'istanza persistente precedente. La disabilitazione temporanea della persistenza può contribuire a identificare il problema. La funzionalità di traccia di WCF può essere utilizzata per visualizzare la chiave di correlazione calcolata ed essere utile per eseguire il debug di questo tipo di problema.

Condizioni di traccia

Tra la ricezione di un messaggio da parte del servizio e il momento in cui la correlazione viene effettivamente inizializzata si verifica un breve intervallo, durante il quale i messaggi seguenti verranno ignorati. Se un servizio flusso di lavoro inizializza la correlazione basata sul contenuto tramite dati passati dal client su un'operazione unidirezionale e il chiamante invia immediatamente messaggi successivi, questi messaggi verranno ignorati durante questo intervallo. È possibile evitare questo problema utilizzando un'operazione bidirezionale per inizializzare la correlazione o un oggetto TransactedReceiveScope.

Problemi relativi alle query di correlazione

Le query di correlazione consentono di specificare i dati di un messaggio da utilizzare per la correlazione del messaggio stesso. Questi dati vengono specificati tramite una query XPath. Se a un servizio non vengono inviati messaggi anche se tutto sembra corretto, una strategia per la risoluzione dei problemi consiste nel specificare un valore letterale corrispondente al valore dei dati del messaggio anziché una query XPath. Per specificare un valore letterale, utilizzare la funzione string. Nell'esempio seguente viene configurato un oggetto MessageQuerySet per l'utilizzo del valore letterale 11445 per OrderId e la query XPath viene impostata come commento.

MessageQuerySet = new MessageQuerySet
{
    {
        "OrderId",
        //new XPathMessageQuery("sm:body()/tempuri:StartOrderResponse/tempuri:OrderId")
        new XPathMessageQuery("string('11445')")
    }
}

Se una query XPath non è configurata correttamente in modo tale che non viene recuperato alcun dato di correlazione, viene restituito un errore con il messaggio seguente: "Una query di correlazione ha restituito un set di risultati vuoto. Assicurarsi che le query di correlazione per l'endpoint siano configurate correttamente". Un modo rapido per risolvere i problemi consiste nel sostituire la query XPath con un valore letterale come descritto nella sezione precedente. Questo problema può verificarsi se si usa il generatore di query XPath nelle finestre di dialogo Aggiungi inizializzatori di correlazione o CorrelatesOn Definition e il servizio flusso di lavoro usa contratti di messaggio. Nell'esempio seguente viene definita una classe dei contratto di messaggio.

[MessageContract]
public class AddItemMessage
{
    [MessageHeader]
    public string CartId;

    [MessageBodyMember]
    public string Item;
}

Questo contratto di messaggio viene utilizzato da un'attività Receive in un flusso di lavoro. Il CartId nell'intestazione del messaggio viene utilizzato per correlare il messaggio all'istanza corretta. Se la query XPath che recupera il CartId viene creata utilizzando le finestre di dialogo di correlazione nella finestra di progettazione del flusso di lavoro, viene generata la seguente query XPath errata.

sm:body()/xg0:AddItemMessage/xg0:CartId

Questa query XPath sarebbe corretta se l'attività Receive utilizzasse i parametri relativi ai dati, ma dal momento che utilizza un contratto di messaggio, non è corretta. La seguenti query XPath è la query XPath corretta per recuperare il CartId dall'intestazione.

sm:header()/tempuri:CartId

Questo può essere confermato esaminando il corpo del messaggio.

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService/AddItem</Action>
    <h:CartId xmlns:h="http://tempuri.org/">80c95b41-c98d-4660-a6c1-99412206e54c</h:CartId>
  </s:Header>
  <s:Body>
    <AddItemMessage xmlns="http://tempuri.org/">
      <Item>Books</Item>
    </AddItemMessage>
  </s:Body>
</s:Envelope>

Nell'esempio riportato di seguito viene illustrata un'attività Receive configurata per un'operazione AddItem che utilizza il contratto di messaggio precedente per ricevere i dati. La query XPath è configurata correttamente.

<Receive CorrelatesWith="[CCHandle] OperationName="AddItem" ServiceContractName="p:IService">
  <Receive.CorrelatesOn>
    <XPathMessageQuery x:Key="key1">
      <XPathMessageQuery.Namespaces>
        <ssx:XPathMessageContextMarkup>
          <x:String x:Key="xg0">http://schemas.datacontract.org/2004/07/MessageContractWFService</x:String>
        </ssx:XPathMessageContextMarkup>
      </XPathMessageQuery.Namespaces>sm:header()/tempuri:CartId</XPathMessageQuery>
  </Receive.CorrelatesOn>
  <ReceiveMessageContent DeclaredMessageType="m:AddItemMessage">
    <p1:OutArgument x:TypeArguments="m:AddItemMessage">[AddItemMessage]</p1:OutArgument>
  </ReceiveMessageContent>
</Receive>