Problemen met correlatie oplossen

Correlatie wordt gebruikt om berichten van werkstroomservices aan elkaar en aan het juiste werkstroomexemplaren te koppelen, maar als deze niet correct is geconfigureerd, worden berichten niet ontvangen en werken toepassingen niet correct. Dit onderwerp bevat een overzicht van verschillende methoden voor het oplossen van correlatieproblemen en bevat ook enkele veelvoorkomende problemen die kunnen optreden wanneer u correlatie gebruikt.

De UnknownMessageReceived-gebeurtenis verwerken

De UnknownMessageReceived gebeurtenis treedt op wanneer een onbekend bericht wordt ontvangen door een service, inclusief berichten die niet kunnen worden gecorreleerd aan een bestaand exemplaar. Voor zelf-hostende services kan deze gebeurtenis worden verwerkt in de hosttoepassing.

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

Voor door het web gehoste services kan deze gebeurtenis worden verwerkt door een klasse af te leiden van WorkflowServiceHostFactory en te CreateWorkflowServiceHostoverschrijven.

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;
    }
}

Deze aangepaste WorkflowServiceHostFactory waarde kan vervolgens worden opgegeven in het svc bestand voor de service.

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

Wanneer deze handler wordt aangeroepen, kan het bericht worden opgehaald met behulp van de Message eigenschap van de UnknownMessageReceivedEventArgs, en zal het op het volgende bericht lijken.

<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>

Het inspecteren van berichten die naar de UnknownMessageReceived handler worden verzonden, kan aanwijzingen geven over waarom het bericht niet overeenkomt met een exemplaar van de werkstroomservice.

Gebruik tracking om de voortgang van de werkstroom te monitoren

Bijhouden biedt een manier om de voortgang van een werkstroom te bewaken. Standaard worden volgrecords verzonden voor werkstroomlevenscyclusgebeurtenissen, activiteitenlevenscyclusgebeurtenissen, fouthantering en hervatting van aanduidingen. Daarnaast kunnen aangepaste traceringsrecords worden verzonden door aangepaste activiteiten. Bij het oplossen van problemen met correlatie zijn de records voor het bijhouden van activiteiten, de records voor het hervatten van bladwijzers en de records voor foutpropagatie het nuttigst. De records voor het bijhouden van activiteiten kunnen worden gebruikt om de huidige voortgang van de werkstroom te bepalen en om te bepalen welke berichtenactiviteit momenteel op berichten wacht. Bladwijzerherstelrecords zijn nuttig omdat ze aangeven dat een bericht is ontvangen door de werkstroom, en foutpropagatierecords leggen eventuele fouten in de werkstroom vast. Om tracering in te schakelen, geeft u het gewenste TrackingParticipant op in de WorkflowExtensions van de WorkflowServiceHost. In het volgende voorbeeld wordt de ConsoleTrackingParticipant (uit het Custom Tracking-voorbeeld) geconfigureerd met behulp van het standaard tracingsprofiel.

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

Een traceringsdeelnemer zoals de ConsoleTrackingParticipant is handig voor zelf-hostende werkstroomservices met een consolevenster. Voor een web-hostende service moet een traceringsdeelnemer die de traceringsgegevens registreert in een duurzame opslag worden gebruikt, zoals de ingebouwde EtwTrackingParticipant, of een aangepaste deelnemer die de gegevens registreert in een bestand.

Zie werkstroomtracking en tracering, het configureren van tracking voor een werkstroom, en de Tracking [WF Samples] samples voor meer informatie over het bijhouden en configureren van tracking voor een web-gehoste werkstroomdienst.

WCF-tracering gebruiken

Met WCF-tracering kan de stroom van berichten naar en van een werkstroomservice gevolgd worden. Deze traceringsgegevens zijn handig bij het oplossen van correlatieproblemen, met name voor correlatie op basis van inhoud. Als u tracering wilt inschakelen, geeft u de gewenste traceerlisteners op in de system.diagnostics sectie van het web.config bestand als de werkstroomservice wordt gehost op het web of het app.config bestand als de werkstroomservice zelf wordt gehost. Als u de inhoud van de berichten in het traceringsbestand wilt opnemen, geeft u true op voor logEntireMessage het messageLogging element in de diagnostics sectie van system.serviceModel. In het volgende voorbeeld is traceringsgegevens, inclusief de inhoud van de berichten, geconfigureerd om naar een bestand met de naam service.svclogte worden geschreven.

<?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>

Om de traceringsinformatie te bekijken die deel uitmaakt van service.svclog, wordt de Service Trace Viewer Tool (SvcTraceViewer.exe) gebruikt. Dit is vooral handig bij het oplossen van correlatieproblemen op basis van inhoud, omdat u de inhoud van het bericht kunt bekijken en precies kunt zien wat er wordt doorgegeven en of deze overeenkomt met de CorrelationQuery correlatie op basis van inhoud. Zie het hulpprogramma Service Trace Viewer (SvcTraceViewer.exe) voor meer informatie over WCF-tracering, het configureren van tracering en het gebruik van tracering om problemen met uw toepassing op te lossen.

Veelvoorkomende problemen met correlatie van Context Exchange

Voor bepaalde typen correlatie moet een specifiek type binding worden gebruikt om de correlatie correct te laten werken. Voorbeelden hiervan zijn correlatie tussen aanvragen en antwoorden. Hiervoor is een binding in twee richtingen vereist, zoals BasicHttpBinding, en contextuitwisselingscorrelatie, waarvoor een contextgebaseerde binding is vereist, zoals BasicHttpContextBinding. De meeste bindingen ondersteunen tweerichtingsbewerkingen, dus dit is geen veelvoorkomend probleem voor de correlatie tussen aanvragen en antwoorden, maar er zijn slechts een handvol contextbindingen, waaronder BasicHttpContextBinding, WSHttpContextBindingen NetTcpContextBinding. Als een van deze bindingen niet wordt gebruikt, slaagt de eerste aanroep naar een werkstroomservice, maar mislukken volgende aanroepen met het volgende 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.

De contextinformatie die wordt gebruikt voor contextcorrelatie, kan worden geretourneerd door de SendReplyReceive activiteit die de contextcorrelatie initialiseert bij het gebruik van een tweerichtingsbewerking, of door de aanroeper kan worden opgegeven als de bewerking in één richting is. Als de context niet wordt verzonden door de aanroeper of wordt geretourneerd door de werkstroomservice, dan wordt hetzelfde FaultException dat eerder beschreven werd, geretourneerd wanneer een volgende bewerking plaatsvindt.

Veelvoorkomende Request-Reply correlatieproblemen

Correlatie tussen aanvragen en antwoorden wordt gebruikt met een Receive/SendReply paar om een tweerichtingsbewerking te implementeren in een werkstroomservice en met een Send/ReceiveReply paar om een tweerichtingsbewerking aan te roepen in een andere webservice. Wanneer u een tweerichtingsbewerking aanroept in een WCF-service, kan de service een traditionele, imperatieve WCF-service zijn of een werkstroomservice zijn. Als u een correlatie tussen aanvragen en antwoorden wilt gebruiken, moet een binding in twee richtingen worden gebruikt, zoals BasicHttpBindingen moeten de bewerkingen in twee richtingen zijn.

Als de werkstroomservice gelijktijdig tweewegbewerkingen of overlappende Receive/SendReply- of Send/ReceiveReply-paren heeft, is het impliciete correlatiebeheer dat wordt geboden door WorkflowServiceHost mogelijk niet voldoende, vooral in sterk belaste scenario's, en worden berichten mogelijk niet correct gerouteerd. Om te voorkomen dat dit probleem optreedt, raden we u aan altijd expliciet een CorrelationHandle correlatie op te geven bij het gebruik van correlatie tussen aanvragen en antwoorden. Wanneer u de sjablonen SendAndReceiveReply en ReceiveAndSendReply gebruikt vanuit de sectie Berichten van de Werkset in de werkstroomontwerper, wordt een CorrelationHandle expliciet geconfigureerd. Bij het bouwen van een werkstroom met behulp van code, wordt de CorrelationHandle opgegeven in de CorrelationInitializers van de eerste activiteit in het paar. In het volgende voorbeeld wordt een Receive activiteit geconfigureerd met een expliciete CorrelationHandle opgegeven in de 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.

Persistentie is niet toegestaan tussen een Receive/SendReply paar of een Send/ReceiveReply paar. Er wordt een zone zonder persistentie gecreëerd die duurt totdat beide activiteiten zijn voltooid. Als een activiteit, zoals een vertragingsactiviteit, zich in deze niet-persistente zone bevindt en ervoor zorgt dat de werkstroom niet actief wordt, blijft de werkstroom niet behouden, zelfs niet als de host is geconfigureerd om werkstromen te behouden wanneer ze niet actief worden. Als een activiteit, zoals een persist-activiteit, probeert zich expliciet in de geen-persistzone te bevinden, loopt het tegen een fatale uitzondering aan, wordt de werkstroom afgebroken en wordt een FaultException aan de aanroeper geretourneerd. Het fatale uitzonderingsbericht is "System.InvalidOperationException: Persistente activiteiten kunnen niet binnen persistentieblokken worden geplaatst.". Deze uitzondering wordt niet geretourneerd naar de beller, maar kan worden waargenomen als bijhouden is ingeschakeld. Het bericht voor de FaultException geretourneerde aanroeper is "De bewerking kan niet worden uitgevoerd omdat WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' is voltooid".

Zie Request-Reply voor meer informatie over correlatie tussen aanvragen en antwoorden.

Veelvoorkomende problemen met correlatie van inhoud

Correlatie op basis van inhoud wordt gebruikt wanneer een werkstroomservice meerdere berichten ontvangt en een stukje gegevens in de uitgewisselde berichten het gewenste exemplaar identificeert. Correlatie op basis van inhoud gebruikt deze gegevens in het bericht, zoals een klantnummer of order-id, om berichten naar het juiste werkstroomexemplaar te routeren. In deze sectie worden verschillende veelvoorkomende problemen beschreven die kunnen optreden bij het gebruik van correlatie op basis van inhoud.

Zorg ervoor dat de identificatiegegevens uniek zijn

De gegevens die worden gebruikt om het exemplaar te identificeren, worden gehasht in een correlatiesleutel. Zorg ervoor dat de gegevens die worden gebruikt voor correlatie uniek zijn, anders kunnen er conflicten in de hash-sleutel optreden en kunnen berichten foutief worden omgeleid. Een correlatie op basis van een klantnaam kan bijvoorbeeld een botsing veroorzaken omdat er mogelijk meerdere klanten zijn die dezelfde naam hebben. De dubbele punt (:) mag niet worden gebruikt als onderdeel van de gegevens die worden gebruikt om het bericht te correleren, omdat het al wordt gebruikt om de sleutel en waarde van de berichtquery te scheiden om de tekenreeks te vormen die vervolgens wordt gehasht. Als persistentie wordt gebruikt, moet u ervoor zorgen dat de huidige identificatiegegevens niet zijn gebruikt door een eerder persistente instantie. Door persistentie tijdelijk uit te schakelen, kan dit probleem worden geïdentificeerd. WCF-tracering kan worden gebruikt om de berekende correlatiesleutel weer te geven en is handig voor het opsporen van fouten in dit soort problemen.

Racevoorwaarden

Er is een klein tijdsverschil tussen de service die een bericht ontvangt en de correlatie daadwerkelijk wordt geïnitialiseerd, waarbij opvolgingsberichten worden genegeerd. Als een werkstroomservice de correlatie op basis van inhoud initialiseert met behulp van gegevens die door de client worden doorgegeven via een bewerking in één richting en de beller directe opvolgingsberichten verzendt, worden deze berichten tijdens dit interval genegeerd. Dit kan worden vermeden door een tweerichtingsbewerking te gebruiken om de correlatie te initialiseren of door een TransactedReceiveScope.

Problemen met correlatiequery's

Correlatiequery's worden gebruikt om op te geven welke gegevens in een bericht worden gebruikt om het bericht te correleren. Deze gegevens worden opgegeven met behulp van een XPath-query. Als berichten naar een service niet worden verzonden, zelfs als alles correct lijkt te zijn, is één strategie voor probleemoplossing het opgeven van een letterlijke waarde die overeenkomt met de waarde van de berichtgegevens in plaats van een XPath-query. Als u een letterlijke waarde wilt opgeven, gebruikt u de string functie. In het volgende voorbeeld wordt een MessageQuerySet geconfigureerd om een letterlijke waarde van 11445 voor de OrderId te gebruiken en is de XPath-query uitgeschakeld.

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

Als een XPath-query onjuist is geconfigureerd, zodat er geen correlatiegegevens worden opgehaald, wordt er een fout geretourneerd met het volgende bericht: 'Een correlatiequery heeft een lege resultatenset opgeleverd. Zorg ervoor dat correlatiequery's voor het eindpunt correct zijn geconfigureerd.' U kunt dit snel oplossen door de XPath-query te vervangen door een letterlijke waarde, zoals beschreven in de vorige sectie. Dit probleem kan optreden als u de opbouwfunctie voor XPath-query's gebruikt in de dialoogvensters Correlatie-initializers toevoegen of CorrelatesOn-definitie en uw werkstroomservice gebruikmaakt van berichtcontracten. In het volgende voorbeeld wordt een berichtcontractklasse gedefinieerd.

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

    [MessageBodyMember]
    public string Item;
}

Dit berichtcontract wordt gebruikt door een Receive activiteit in een werkstroom. De CartId in de koptekst van het bericht wordt gebruikt om het bericht te correleren met het juiste exemplaar. Als de XPath-query waarmee de CartId query wordt opgehaald, wordt gemaakt met behulp van de correlatiedialoogvensters in de werkstroomontwerper, wordt de volgende onjuiste XPath-query gegenereerd.

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

Deze XPath-query zou juist zijn als de Receive activiteit parameters voor de gegevens heeft gebruikt, maar omdat deze gebruikmaakt van een berichtcontract, is dit onjuist. De volgende XPath-query is de juiste XPath-query om de CartId op te halen van de header.

sm:header()/tempuri:CartId

Dit kan worden bevestigd door de hoofdtekst van het bericht te onderzoeken.

<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>

In het volgende voorbeeld ziet u een Receive activiteit die is geconfigureerd voor een AddItem bewerking die gebruikmaakt van het vorige berichtcontract om gegevens te ontvangen. De XPath-query is correct geconfigureerd.

<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>