Dela via


Felsöka korrelation

Korrelation används för att relatera arbetsflödestjänstmeddelanden till varandra och till rätt arbetsflödesinstans, men om den inte är korrekt konfigurerad tas meddelanden inte emot och programmen fungerar inte korrekt. Det här avsnittet innehåller en översikt över flera metoder för felsökning av korrelationsproblem och innehåller även några vanliga problem som kan uppstå när du använder korrelation.

Hantera händelsen UnknownMessageReceived

Händelsen UnknownMessageReceived inträffar när ett okänt meddelande tas emot av en tjänst, inklusive meddelanden som inte kan korreleras till en befintlig instans. För lokalt installerade tjänster kan den här händelsen hanteras i värdprogrammet.

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

För webbaserade tjänster kan den här händelsen hanteras genom att härleda en klass från WorkflowServiceHostFactory och åsidosätta 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;
    }
}

Den här anpassade WorkflowServiceHostFactory filen kan sedan anges i svc filen för tjänsten.

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

När den här hanteraren anropas kan meddelandet hämtas med hjälp Message av UnknownMessageReceivedEventArgsegenskapen , och liknar följande meddelande.

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

Att inspektera meddelanden som skickas till UnknownMessageReceived hanteraren kan ge ledtrådar om varför meddelandet inte korrelerade med en instans av arbetsflödestjänsten.

Använda spårning för att övervaka arbetsflödets förlopp

Spårning är ett sätt att övervaka förloppet för ett arbetsflöde. Som standard genereras spårningsposter för arbetsflödets livscykelhändelser, aktivitetslivscykelhändelser, felspridning och återupptagande av bokmärken. Dessutom kan anpassade spårningsposter genereras av anpassade aktiviteter. När du felsöker korrelation är aktivitetsspårningsposterna, återtagningsposterna för bokmärket och felspridningsposterna de mest användbara. Aktivitetsspårningsposterna kan användas för att fastställa arbetsflödets aktuella förlopp och kan hjälpa dig att identifiera vilken meddelandeaktivitet som väntar på meddelanden. Återtagningsposter för bokmärken är användbara eftersom de anger att ett meddelande togs emot av arbetsflödet, och felspridningsposter ger en post med eventuella fel i arbetsflödet. Om du vill aktivera spårning anger du önskat TrackingParticipant i WorkflowExtensions för WorkflowServiceHost. I följande exempel ConsoleTrackingParticipant konfigureras (från exemplet anpassad spårning ) med hjälp av standardspårningsprofilen.

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

En spårningsdeltagare som ConsoleTrackingParticipant är användbar för lokalt installerade arbetsflödestjänster som har ett konsolfönster. För en värdbaserad tjänst ska en spårningsdeltagare som loggar spårningsinformationen till ett varaktigt arkiv användas, till exempel den inbyggda EtwTrackingParticipant, eller en anpassad spårningsdeltagare som loggar informationen till en fil.

Mer information om hur du spårar och konfigurerar spårning för en webbhanterad arbetsflödestjänst finns i Arbetsflödesspårning och spårning, Konfigurera spårning för ett arbetsflöde och exempel på spårning [WF-exempel].

Använda WCF-spårning

WCF-spårning ger spårning av flödet av meddelanden till och från en arbetsflödestjänst. Den här spårningsinformationen är användbar när du felsöker korrelationsproblem, särskilt för innehållsbaserad korrelation. Om du vill aktivera spårning anger du önskade spårningslyssnare i system.diagnostics avsnittet web.config i filen om arbetsflödestjänsten är webbaserad eller app.config filen om arbetsflödestjänsten är lokalt installerad. Om du vill inkludera innehållet i meddelandena i spårningsfilen anger du true för i -elementet diagnosticsmessageLogging i avsnittet i system.serviceModellogEntireMessage . I följande exempel konfigureras spårningsinformation, inklusive innehållet i meddelandena, så att den skrivs till en fil med namnet 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>

Om du vill visa spårningsinformationen som finns i service.svcloganvänds servicespårningsverktyget (SvcTraceViewer.exe). Detta är särskilt användbart när du felsöker problem med innehållsbaserad korrelation eftersom du kan visa meddelandeinnehållet och se exakt vad som skickas och om det matchar för den innehållsbaserade korrelationen CorrelationQuery . Mer information om WCF-spårning finns i Service Trace Viewer Tool (SvcTraceViewer.exe), Konfigurera spårning och Använda spårning för att felsöka ditt program.

Vanliga problem med exchange-korrelation för kontext

Vissa typer av korrelation kräver att en specifik typ av bindning används för att korrelationen ska fungera korrekt. Exempel är korrelation mellan begäran och svar, som kräver en dubbelriktad bindning, till BasicHttpBindingexempel , och korrelation för kontextutbyte, som kräver en kontextbaserad bindning, BasicHttpContextBindingtill exempel . De flesta bindningar stöder dubbelriktade åtgärder, så det här är inte ett vanligt problem för korrelation mellan begäran och svar, men det finns bara en handfull kontextbaserade bindningar, inklusive BasicHttpContextBinding, WSHttpContextBindingoch NetTcpContextBinding. Om en av dessa bindningar inte används lyckas det första anropet till en arbetsflödestjänst, men efterföljande anrop misslyckas med följande 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.

Kontextinformationen som används för kontextkorrelation kan returneras av SendReply till-aktiviteten Receive som initierar kontextkorrelationen när du använder en dubbelriktad åtgärd, eller så kan den anges av anroparen om åtgärden är enkelriktad. Om kontexten inte skickas av anroparen eller returneras av arbetsflödestjänsten returneras samma FaultException som beskrivits tidigare när en efterföljande åtgärd anropas.

Vanliga Request-Reply korrelationsproblem

Korrelation mellan begäran och svar används med ett Receive/SendReply par för att implementera en dubbelriktad åtgärd i en arbetsflödestjänst och med ett Send/ReceiveReply par som anropar en dubbelriktad åtgärd i en annan webbtjänst. När du anropar en dubbelriktad åtgärd i en WCF-tjänst kan tjänsten antingen vara en traditionell imperativ kodbaserad WCF-tjänst eller en arbetsflödestjänst. Om du vill använda korrelation mellan begäran och svar måste en tvåvägsbindning användas, till exempel BasicHttpBinding, och åtgärderna måste vara dubbelriktade.

Om arbetsflödestjänsten har dubbelriktade åtgärder parallellt, överlappande Receive/SendReply ellerReceiveReplySend/par, kanske den implicita hantering av korrelationshandtaget som tillhandahålls av WorkflowServiceHost inte är tillräcklig, särskilt i scenarier med hög stress, och meddelanden kanske inte dirigeras korrekt. För att förhindra att det här problemet uppstår rekommenderar vi att du alltid uttryckligen anger en CorrelationHandle när du använder korrelation mellan begäran och svar. När du använder mallarna SendAndReceiveReply och ReceiveAndSendReply från meddelandeavsnittet i verktygslådan i arbetsflödesdesignern konfigureras a CorrelationHandle explicit som standard. När du skapar ett arbetsflöde med hjälp av kod CorrelationHandle anges i den CorrelationInitializers första aktiviteten i paret. I följande exempel konfigureras en Receive aktivitet med en explicit CorrelationHandle angiven i 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.

Beständighet är inte tillåtet mellan ett Receive/SendReply par eller ett Send/ReceiveReply par. En no-persist-zon skapas som varar tills båda aktiviteterna har slutförts. Om en aktivitet, till exempel en fördröjningsaktivitet, finns i den här zonen utan kvarhåll och gör att arbetsflödet blir inaktivt, kommer arbetsflödet inte att sparas även om värden är konfigurerad för att spara arbetsflöden när de blir inaktiva. Om en aktivitet, till exempel en beständig aktivitet, försöker att uttryckligen finnas kvar i zonen ingen beständig genereras ett allvarligt undantag, arbetsflödet avbryts och ett FaultException returneras till anroparen. Det allvarliga undantagsmeddelandet är "System.InvalidOperationException: Persist activities cannot be contained within no persistence blocks". Det här undantaget returneras inte till anroparen, men kan observeras om spårning är aktiverat. Meddelandet för den FaultException som returneras till anroparen är "Åtgärden kunde inte utföras eftersom WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' har slutförts".

Mer information om korrelation mellan begäran och svar finns i Request-Reply(Begäran-svar).

Vanliga problem med innehållskorrelation

Innehållsbaserad korrelation används när en arbetsflödestjänst tar emot flera meddelanden och en del data i de utväxlade meddelandena identifierar den önskade instansen. Innehållsbaserad korrelation använder dessa data i meddelandet, till exempel ett kundnummer eller order-ID, för att dirigera meddelanden till rätt arbetsflödesinstans. Det här avsnittet beskriver flera vanliga problem som kan uppstå när du använder innehållsbaserad korrelation.

Se till att identifiera data är unika

De data som används för att identifiera instansen hashas in i en korrelationsnyckel. Var noga med att säkerställa att de data som används för korrelation är unika, annars kan kollisioner i hash-nyckeln inträffa och orsaka att meddelanden felutlöss. Till exempel kan en korrelation som endast baseras på ett kundnamn orsaka en kollision eftersom det kan finnas flera kunder som har samma namn. Kolonet (:) bör inte användas som en del av de data som används för att korrelera meddelandet eftersom det redan används för att avgränsa meddelandefrågans nyckel och värde för att bilda strängen som därefter hashats. Om beständighet används kontrollerar du att aktuella identifierande data inte har använts av en tidigare bevarad instans. Att tillfälligt inaktivera beständighet kan hjälpa dig att identifiera det här problemet. WCF-spårning kan användas för att visa den beräknade korrelationsnyckeln och är användbar för felsökning av den här typen av problem.

Tävlingsförhållanden

Det finns ett litet tidsintervall mellan att tjänsten tar emot ett meddelande och korrelationen faktiskt initieras, under vilken uppföljningsmeddelanden ignoreras. Om en arbetsflödestjänst initierar den innehållsbaserade korrelationen med hjälp av data som skickas från klienten via en enkelriktad åtgärd, och anroparen skickar omedelbara uppföljningsmeddelanden, ignoreras dessa meddelanden under det här intervallet. Detta kan undvikas genom att använda en dubbelriktad åtgärd för att initiera korrelationen eller med hjälp av en TransactedReceiveScope.

Problem med korrelationsfråga

Korrelationsfrågor används för att ange vilka data i ett meddelande som används för att korrelera meddelandet. Dessa data anges med hjälp av en XPath-fråga. Om meddelanden till en tjänst inte skickas trots att allt verkar vara korrekt är en strategi för felsökning att ange ett literalvärde som matchar värdet för meddelandedata i stället för en XPath-fråga. Om du vill ange ett literalvärde använder du string funktionen . I följande exempel är en MessageQuerySet konfigurerad för att använda ett literalvärde 11445 för för OrderId och XPath-frågan kommenteras ut.

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

Om en XPath-fråga är felaktigt konfigurerad så att inga korrelationsdata hämtas returneras ett fel med följande meddelande: "En korrelationsfråga gav en tom resultatuppsättning. Kontrollera att korrelationsfrågor för slutpunkten är korrekt konfigurerade." Ett snabbt sätt att felsöka detta är att ersätta XPath-frågan med ett literalvärde enligt beskrivningen i föregående avsnitt. Det här problemet kan inträffa om du använder XPath-frågeverktyget i dialogrutorna Lägg till korrelationsinitierare eller KorrelatesOn Definition och arbetsflödestjänsten använder meddelandekontrakt. I följande exempel definieras en meddelandekontraktsklass.

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

    [MessageBodyMember]
    public string Item;
}

Det här meddelandekontraktet används av en Receive aktivitet i ett arbetsflöde. I CartId rubriken i meddelandet används för att korrelera meddelandet till rätt instans. Om XPath-frågan som hämtar CartId skapas med hjälp av korrelationsdialogrutorna i arbetsflödesdesignern genereras följande felaktiga XPath-fråga.

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

Den här XPath-frågan skulle vara korrekt om aktiviteten Receive använde parametrar för data, men eftersom den använder ett meddelandekontrakt är den felaktig. Följande XPath-fråga är rätt XPath-fråga för att hämta CartId från huvudet.

sm:header()/tempuri:CartId

Detta kan bekräftas genom att undersöka meddelandets brödtext.

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

I följande exempel visas en Receive aktivitet som har konfigurerats för en AddItem åtgärd som använder det tidigare meddelandekontraktet för att ta emot data. XPath-frågan är korrekt konfigurerad.

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