Řešení potíží s korelací

Korelace se používá k vzájemné relaci zpráv služby pracovního postupu a správné instanci pracovního postupu, ale pokud není správně nakonfigurovaná, zprávy nebudou přijaty a aplikace nebudou správně fungovat. Toto téma obsahuje přehled několika metod pro řešení problémů s korelací a uvádí také některé běžné problémy, ke kterým může dojít při použití korelace.

Zpracování události UnknownMessageReceived

Událost UnknownMessageReceived nastane, když služba přijme neznámou zprávu, včetně zpráv, které nelze korelovat s existující instancí. U služeb v místním prostředí je možné tuto událost zpracovat v hostitelské aplikaci.

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

U služeb hostovaných na webu lze tuto událost zpracovat odvozením třídy z WorkflowServiceHostFactory a přepsáním 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;
    }
}

Tento vlastní WorkflowServiceHostFactory je pak možné zadat v svc souboru pro službu.

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

Při vyvolání této obslužné rutiny lze zprávu načíst pomocí Message vlastnosti objektu UnknownMessageReceivedEventArgs, a bude vypadat podobně jako následující zpráva.

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

Kontrola zpráv odeslaných do UnknownMessageReceived obslužné rutiny může poskytnout náznaky o tom, proč zpráva nekorelovala s instancí služby pracovního postupu.

Monitorování průběhu pracovního postupu pomocí sledování

Sledování poskytuje způsob, jak sledovat průběh pracovního postupu. Ve výchozím nastavení se záznamy sledování generují pro události životního cyklu pracovního postupu, události životního cyklu aktivity, šíření chyb a obnovení záložek. Vlastní záznamy sledování mohou být navíc generovány vlastními aktivitami. Při řešení potíží s korelací jsou nejvíce užitečné záznamy sledování aktivit, záznamy obnovení záložek a záznamy propagace chyb. Záznamy sledování aktivit se dají použít k určení aktuálního průběhu pracovního postupu a můžou pomoct určit, která aktivita zasílání zpráv aktuálně čeká na zprávy. Záznamy obnovení záložky jsou užitečné, protože označují, že pracovní postup přijal zprávu a záznamy šíření chyb poskytují záznam o všech chybách v pracovním postupu. Chcete-li povolit sledování, zadejte požadovaný TrackingParticipant v WorkflowExtensions objektu WorkflowServiceHost. V následujícím příkladu je ConsoleTrackingParticipant (z ukázky vlastního sledování) nakonfigurován pomocí výchozího profilu sledování.

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

Účastník sledování, jako je ConsoleTrackingParticipant, je užitečný pro samostatně hostované služby pracovního postupu, které mají okno konzoly. U služby hostované na webu by se měl použít účastník sledování, který protokoluje informace o sledování do odolného úložiště, například předdefinovaný EtwTrackingParticipantnebo vlastní účastník sledování, který protokoluje informace do souboru.

Další informace o sledování a konfiguraci sledování pro službu pracovních postupů s webovým hostováním naleznete v tématu Sledování a trasování pracovních postupů, Konfigurace sledování pro pracovní postup a v ukázkách Sledování [WF].

Použití trasování WCF

Trasování WCF poskytuje trasování toku zpráv do a ze služby pracovního postupu. Tyto informace o trasování jsou užitečné při řešení problémů s korelací, zejména pro korelaci založenou na obsahu. Pokud chcete povolit trasování, zadejte požadované naslouchací procesy trasování v části system.diagnostics souboru web.config, pokud je služba pracovního postupu hostovaná na webu, nebo v souboru app.config, pokud je služba pracovního postupu hostovaná samostatně. Chcete-li zahrnout obsah zpráv v trasovacím souboru, zadejte true pro logEntireMessage prvku messageLogging v části diagnostics oddílu system.serviceModel. V následujícím příkladu jsou informace o trasování, včetně obsahu zpráv, nakonfigurovány tak, aby byly zapsány do souboru s názvem 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>

Pro zobrazení trasovacích informací obsažených v service.svclog se používá nástroj Service Trace Viewer (SvcTraceViewer.exe). To je zvlášť užitečné při řešení problémů korelací založených na obsahu, protože můžete zobrazit obsah zprávy a zjistit, co přesně se předává, a to, jestli odpovídá korelaci založené na CorrelationQuery obsahu. Další informace o trasování WCF naleznete v tématu Service Trace Viewer Tool (SvcTraceViewer.exe), konfigurace trasování a použití trasování k řešení potíží s aplikací.

Běžné problémy s korelací při výměně kontextových dat

Určité typy korelace vyžadují, aby pro správné fungování korelace byl použit konkrétní typ vazby. Mezi příklady patří korelace požadavek-odpověď, která vyžaduje obousměrnou vazbu, například BasicHttpBinding, a korelace výměny kontextu, která vyžaduje vazbu založenou na kontextu, například BasicHttpContextBinding. Většina vazeb podporuje obousměrné operace, takže se nejedná o běžný problém pro korelaci odpovědí na žádost, ale existuje pouze několik kontextových vazeb, mezi které patří BasicHttpContextBinding, WSHttpContextBindinga NetTcpContextBinding. Pokud se některá z těchto vazeb nepoužívá, počáteční volání služby pracovního postupu bude úspěšné, ale následná volání selžou s následujícím kódem 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.

Kontextové informace, které se používají pro korelaci kontextu, mohou být vráceny SendReplyReceive aktivitou, která inicializuje kontextovou korelaci při použití obousměrné operace, nebo je možné určit volajícím, pokud je operace jednosměrná. Pokud kontext není odeslán volajícím nebo vrácen službou pracovního postupu, při následném provedení operace se vrátí stejná FaultException jako byla uvedena dříve.

Běžné problémy s korelací Request-Reply

Korelace odpovědí na žádost se používá s párem Receive/SendReply k implementaci obousměrné operace ve službě pracovního postupu a s Send/ReceiveReply dvojicí, která vyvolá obousměrnou operaci v jiné webové službě. Při vyvolání obousměrné operace ve službě WCF může být služba buď tradiční imperativní službou WCF založenou na kódu, nebo může být službou pracovního postupu. Pokud chcete použít korelaci odpovědi na požadavek, musí se použít obousměrná vazba, například BasicHttpBindinga operace musí být obousměrné.

Pokud má služba pracovního postupu obousměrné operace paralelně, nebo překrývající se páry Receive/SendReply a Send/ReceiveReply, nemusí být správa implicitních korelačních úchytů poskytovaná WorkflowServiceHost dostatečná, zejména ve scénářích s vysokým zatížením, a zprávy nemusí být správně směrovány. Pokud chcete zabránit výskytu tohoto problému, doporučujeme při použití korelace odpovědi na požadavek vždy explicitně zadat CorrelationHandle . Pokud v návrháři pracovního postupu používáte šablony SendAndReceiveReply a ReceiveAndSendReply z části Zasílání zpráv, CorrelationHandle je ve výchozím nastavení explicitně nakonfigurována. Při sestavování pracovního postupu pomocí kódu je CorrelationHandle určen v rámci CorrelationInitializers první aktivity v páru. V následujícím příkladu je aktivita Receive nakonfigurována s explicitním CorrelationHandle zadaným v 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.

Trvalost není povolená mezi párem Receive/SendReply nebo párem Send/ReceiveReply . Vytvoří se zóna bez trvalého uložení, která trvá, dokud nejsou obě aktivity dokončeny. Pokud je aktivita, jako například aktivita zpoždění, v této zóně bez uchování a způsobí, že pracovní postup bude nečinný, pracovní postup se neuloží, i když je hostitel nakonfigurován tak, aby pracovní postupy uchovával, když se stanou nečinnými. Pokud se aktivita, například aktivita trvalého uložení, pokusí explicitně uložit v zóně bez uložení, je vyvolána závažná výjimka, pracovní postup se přeruší a FaultException je vráceno volajícímu. Závažná zpráva o výjimce je System.InvalidOperationException: Trvalé aktivity nelze obsahovat v žádném bloku trvalosti. Tato výjimka není vrácena volajícímu, ale je možné ji zjistit, pokud je povoleno sledování. Zpráva vrácená FaultException volajícímu je "Operaci nelze provést, protože WorkflowInstance '5836145b-7da2-49d0-a052-a49162adeab6' byl dokončen".

Další informace o korelaci požadavků a odpovědí najdete v tématu Žádost-Odpověď.

Běžné problémy s korelací obsahu

Korelace založená na obsahu se používá, když služba pracovního postupu přijímá více zpráv a část dat v vyměňovaných zprávách identifikuje požadovanou instanci. Korelace založená na obsahu používá tato data ve zprávě, například číslo zákazníka nebo ID objednávky, ke směrování zpráv do správné instance pracovního postupu. Tato část popisuje několik běžných problémů, ke kterým může dojít při použití korelace založené na obsahu.

Ujistěte se, že identifikace dat je jedinečná.

Data použitá k identifikaci instance jsou hashována do korelačního klíče. Je potřeba dbát na to, aby se zajistilo, že data používaná pro korelaci jsou jedinečná nebo jinak kolize v hashovacím klíči mohou nastat a způsobit chybné přesměrování zpráv. Například korelace založená pouze na jménu zákazníka může způsobit kolize, protože může existovat více zákazníků se stejným názvem. Dvojtečka (:) by neměla být použita jako součást dat, která se používají ke korelaci zprávy, protože se již používá k oddělení klíče a hodnoty dotazu zprávy k vytvoření řetězce, který je následně hashován. Pokud se používá perzistence, ujistěte se, že aktuální identifikační data nebyla použita dříve uloženou instancí. Dočasné zakázání perzistence může pomoct s identifikací tohoto problému. Trasování WCF lze použít k zobrazení vypočítaného korelačního klíče, které je užitečné pro ladění tohoto typu problému.

Podmínky časování

Mezi okamžikem, kdy služba přijme zprávu, a skutečnou inicializací korelace je malá časová mezera, během níž budou ignorovány následné zprávy. Pokud služba pracovního postupu inicializuje korelaci založenou na obsahu pomocí dat předávaných z klienta prostřednictvím jednosměrné operace a volající odešle okamžité následné zprávy, budou tyto zprávy během tohoto intervalu ignorovány. Můžete tomu zabránit použitím obousměrné operace k inicializaci korelace nebo pomocí TransactedReceiveScope.

Problémy s korelačními dotazy

Korelační dotazy slouží k určení dat ve zprávě, která se používají ke korelaci zprávy. Tato data jsou určena pomocí dotazu XPath. Pokud se zprávy do služby neodesílají, i když všechno vypadá správně, je jednou strategií řešení potíží zadat literálovou hodnotu, která odpovídá hodnotě dat zprávy místo dotazu XPath. Chcete-li zadat literální hodnotu, použijte funkci string. V následujícím příkladu je MessageQuerySet nakonfigurováno k použití literální hodnoty 11445 pro OrderId a dotaz XPath je okomentován.

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

Pokud je dotaz XPath správně nakonfigurovaný tak, aby se nenačetla žádná data korelace, vrátí se chyba s následující zprávou: "Dotaz korelace přinesl prázdnou sadu výsledků. Ujistěte se, že jsou správně nakonfigurované korelační dotazy pro koncový bod. Jedním z rychlých způsobů, jak tento problém vyřešit, je nahradit dotaz XPath hodnotou literálu, jak je popsáno v předchozí části. K tomuto problému může dojít, pokud použijete tvůrce dotazů XPath v dialogových oknech Přidat inicializátory korelace nebo CorrelationsOn Definition a služba pracovního postupu používá kontrakty zpráv. V následujícím příkladu je definována třída kontraktu zprávy.

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

    [MessageBodyMember]
    public string Item;
}

Tento kontrakt zprávy je používán aktivitou Receive v pracovním postupu. V záhlaví zprávy CartId se používá pro korelaci zprávy se správnou instancí. Pokud se dotaz XPath, který načte, CartId vytvoří pomocí dialogových oken korelace v návrháři pracovního postupu, vygeneruje se následující nesprávný dotaz XPath.

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

Tento dotaz XPath by byl správný, pokud by aktivita Receive použila parametry pro data, ale protože používá kontrakt na zprávy, je nesprávný. Následující dotaz XPath je správný dotaz XPath pro načtení CartId z hlavičky.

sm:header()/tempuri:CartId

To lze potvrdit prozkoumáním textu zprávy.

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

Následující příklad ukazuje aktivitu nakonfigurovanou ReceiveAddItem pro operaci, která používá předchozí kontrakt zprávy k příjmu dat. Dotaz XPath je správně nakonfigurovaný.

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