Problemen met correlatie oplossen
Correlatie wordt gebruikt om berichten van de werkstroomservice aan elkaar en aan het juiste werkstroomexemplaren te koppelen, maar als deze niet juist is geconfigureerd, worden er geen berichten ontvangen en werken toepassingen niet goed. In dit onderwerp vindt u een overzicht van verschillende methoden voor het oplossen van correlatieproblemen en worden ook enkele veelvoorkomende problemen vermeld die kunnen optreden wanneer u correlatie gebruikt.
De gebeurtenis UnknownMessageReceived 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 web-gehoste services kan deze gebeurtenis worden verwerkt door een klasse af te leiden van WorkflowServiceHostFactory en te overschrijven 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;
}
}
Deze aangepaste WorkflowServiceHostFactory 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 UnknownMessageReceivedEventArgsen lijkt het op het volgende bericht.
<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 zijn verzonden, kan aanwijzingen geven over waarom het bericht niet correleerde met een exemplaar van de werkstroomservice.
Bijhouden gebruiken om de voortgang van de werkstroom te bewaken
Bijhouden biedt een manier om de voortgang van een werkstroom te bewaken. Standaard worden traceringsrecords verzonden voor levenscyclusgebeurtenissen van werkstromen, levenscyclusgebeurtenissen van activiteiten, foutdoorgifte en bladwijzerhervatting. 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 record voor het hervatten van bladwijzers en de foutdoorgifterecords het nuttigst. De records voor het bijhouden van activiteiten kunnen worden gebruikt om de huidige voortgang van de werkstroom te bepalen en kunnen helpen identificeren welke berichtenactiviteit momenteel wacht op berichten. Records voor het hervatten van bladwijzers zijn handig omdat ze aangeven dat er een bericht is ontvangen door de werkstroom, en records voor foutdoorgifte bieden een record van eventuele fouten in de werkstroom. Als u het bijhouden wilt inschakelen, geeft u de gewenste TrackingParticipant op in de WorkflowExtensions van de WorkflowServiceHost. In het volgende voorbeeld wordt de ConsoleTrackingParticipant
(uit het voorbeeld aangepaste tracering ) geconfigureerd met behulp van het standaardtraceringsprofiel.
host.WorkflowExtensions.Add(new ConsoleTrackingParticipant());
Een traceringsdeelnemer zoals de ConsoleTrackingParticipant is handig voor zelf-hostende werkstroomservices die een consolevenster hebben. Voor een web-gehoste service moet een traceringsdeelnemer die de traceringsgegevens registreert in een duurzaam archief worden gebruikt, zoals de ingebouwde EtwTrackingParticipant, of een aangepaste traceringsdeelnemer die de gegevens in een bestand registreert.
Zie Voor meer informatie over het bijhouden en configureren van tracering voor een web-gehoste werkstroomservice , Werkstroom bijhouden en traceren, Tracering configureren voor een werkstroom en de tracering [WF-voorbeelden] voorbeelden.
WCF-tracering gebruiken
WCF-tracering biedt tracering van de stroom berichten van en naar een werkstroomservice. Deze traceringsinformatie is handig bij het oplossen van correlatieproblemen, met name voor correlatie op basis van inhoud. Als u tracering wilt inschakelen, geeft u de gewenste traceringslisteners op in de system.diagnostics
sectie van het web.config
bestand als de werkstroomservice op het web wordt gehost, of het app.config
bestand als de werkstroomservice zelf-hostend is. Als u de inhoud van de berichten in het traceringsbestand wilt opnemen, geeft u true
voor logEntireMessage
op in het messageLogging
-element in de diagnostics
sectie van system.serviceModel
. In het volgende voorbeeld wordt traceringsinformatie, inclusief de inhoud van de berichten, geconfigureerd om te worden geschreven naar een bestand met de naam 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>
Als u de traceringsgegevens in service.svclog
wilt weergeven, wordt het hulpprogramma Service Trace Viewer (SvcTraceViewer.exe) gebruikt. Dit is met name 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 voor de correlatie op basis van inhoud. Zie Service Trace Viewer Tool (SvcTraceViewer.exe),Tracing configureren en Tracering gebruiken om problemen met uw toepassing op te lossen voor meer informatie over WCF-tracering.
Veelvoorkomende correlatieproblemen met contextuitwisseling
Bepaalde typen correlatie vereisen dat een specifiek type binding wordt gebruikt om de correlatie correct te laten werken. Voorbeelden zijn aanvraag-antwoordcorrelatie, waarvoor een tweerichtingsbinding zoals BasicHttpBindingvereist is, en contextuitwisselingscorrelatie, waarvoor een contextgebaseerde binding is vereist, zoals BasicHttpContextBinding. De meeste bindingen ondersteunen bewerkingen in twee richtingen, dus dit is geen veelvoorkomend probleem voor de correlatie tussen aanvragen en antwoorden, maar er zijn slechts een handvol contextgebaseerde bindingen, waaronder BasicHttpContextBinding, WSHttpContextBindingen NetTcpContextBinding. Als een van deze bindingen niet wordt gebruikt, slaagt de eerste aanroep naar een werkstroomservice, maar mislukken volgende aanroepen met de 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 SendReply naar de Receive activiteit die de contextcorrelatie initialiseert bij het gebruik van een tweerichtingsbewerking, of kan worden opgegeven door de aanroeper als de bewerking in één richting is. Als de context niet wordt verzonden door de aanroeper of wordt geretourneerd door de werkstroomservice, wordt het eerder FaultException beschreven resultaat geretourneerd wanneer een volgende bewerking wordt aangeroepen.
Veelvoorkomende Request-Reply correlatieproblemen
Aanvraag-antwoordcorrelatie wordt gebruikt met een Receive/SendReply paar om een tweerichtingsbewerking in een werkstroomservice te implementeren en met een Send/ReceiveReply paar dat een tweerichtingsbewerking in een andere webservice aanroept. Wanneer u een tweerichtingsbewerking in een WCF-service aanroept, kan de service een traditionele WCF-service op basis van imperatieve code of een werkstroomservice zijn. Als u aanvraag-antwoordcorrelatie wilt gebruiken, moet een tweerichtingsbinding worden gebruikt, zoals BasicHttpBinding, en moeten de bewerkingen in twee richtingen zijn.
Als de werkstroomservice parallelle tweerichtingsbewerkingen of overlappende Receive/SendReply of Send/ReceiveReply paren heeft, is het impliciete correlatiebeheer WorkflowServiceHost van mogelijk niet voldoende, met name in scenario's met hoge stress, en worden berichten mogelijk niet correct gerouteerd. Om te voorkomen dat dit probleem optreedt, raden we u aan om altijd expliciet een CorrelationHandle op te geven wanneer u correlatie tussen aanvragen en antwoorden gebruikt. Wanneer u de sjablonen SendAndReceiveReply en ReceiveAndSendReply uit de sectie Berichten van de werkset in de werkstroomontwerper gebruikt, wordt een CorrelationHandle expliciet standaard 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 die is 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 niet-persistente zone gemaakt 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 inactief wordt, blijft de werkstroom niet behouden, zelfs niet als de host is geconfigureerd om werkstromen te behouden wanneer ze inactief zijn. Als een activiteit, zoals een persistente activiteit, expliciet in de zone zonder persistentheid probeert te blijven, treedt er een fatale uitzondering op, wordt de werkstroom afgebroken en wordt een FaultException geretourneerd naar de aanroeper. Het fatale uitzonderingsbericht is 'System.InvalidOperationException: Persistent activities cannot be contained within no persistence blocks'. Deze uitzondering wordt niet geretourneerd naar de aanroeper, maar kan worden waargenomen als tracering is ingeschakeld. Het bericht voor de FaultException geretourneerd aan de aanroeper is 'De bewerking kan niet worden uitgevoerd omdat WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' is voltooid'.
Zie Request-Reply voor meer informatie over de correlatie tussen aanvragen en antwoorden.
Veelvoorkomende problemen met inhoudscorrelatie
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 werkstroomexemplaren 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 naar een correlatiesleutel. Zorg ervoor dat de gegevens die worden gebruikt voor correlatie uniek zijn, anders kunnen er conflicten in de gehashte sleutel optreden waardoor berichten verkeerd worden doorgestuurd. Een correlatie die alleen is gebaseerd op de naam van een klant, kan bijvoorbeeld een botsing veroorzaken omdat er meerdere klanten met dezelfde naam kunnen zijn. De dubbele punt (:) mag niet worden gebruikt als onderdeel van de gegevens die worden gebruikt om het bericht te correleren, omdat dit 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 persistent exemplaar. 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 die daadwerkelijk wordt geïnitialiseerd, waarbij vervolgberichten worden genegeerd. Als een werkstroomservice de correlatie op basis van inhoud initialiseert met behulp van gegevens die via een eenrichtingsbewerking van de client worden doorgegeven, en de aanroeper onmiddellijk opvolgende berichten verzendt, worden deze berichten tijdens dit interval genegeerd. Dit kan worden voorkomen door een tweerichtingsbewerking te gebruiken om de correlatie te initialiseren of door een TransactedReceiveScopete gebruiken.
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, hoewel alles correct lijkt te zijn, is een strategie voor het oplossen van problemen het opgeven van een letterlijke waarde die overeenkomt met de waarde van de berichtgegevens in plaats van een XPath-query. Gebruik de string
functie om een letterlijke waarde op te geven. In het volgende voorbeeld is een MessageQuerySet geconfigureerd om een letterlijke waarde van 11445
te gebruiken voor en OrderId
de XPath-query wordt 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 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.' Een snelle manier om dit op te lossen, is 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 het dialoogvenster Initializers voor correlatie toevoegen of Correleren aan 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 die de CartId
ophaalt, 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 correct zijn als de Receive activiteit parameters voor de gegevens gebruikt, maar omdat er een berichtcontract wordt gebruikt, is deze onjuist. De volgende XPath-query is de juiste XPath-query om de CartId
op te halen uit de header.
sm:header()/tempuri:CartId
Dit kan worden bevestigd door de hoofdtekst van het bericht te bekijken.
<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>