Domanda

quindi devo questo requisito per dare il via attività previste per me a run-time. Per facilitare questo, ho istituito un WorkflowService che riceve Attività come XAML, li idrata, e calcia fuori.

Suoni abbastanza semplice ...

... questo è il mio WorkflowService in XAML

<Activity 
    x:Class="Workflow.Services.WorkflowService.WorkflowService" 
    ...
    xmlns:local1="clr-namespace:Workflow.Activities" >
  <Sequence sap:VirtualizedContainerService.HintSize="277,272">
    <Sequence.Variables>
      <Variable x:TypeArguments="local:Workflow" Name="Workflow" />
    </Sequence.Variables>
    <sap:WorkflowViewStateService.ViewState>
      <scg3:Dictionary x:TypeArguments="x:String, x:Object">
        <x:Boolean x:Key="IsExpanded">True</x:Boolean>
      </scg3:Dictionary>
    </sap:WorkflowViewStateService.ViewState>
    <p:Receive CanCreateInstance="True" DisplayName="ReceiveSubmitWorkflow" sap:VirtualizedContainerService.HintSize="255,86" OperationName="SubmitWorkflow" ServiceContractName="IWorkflowService">
      <p:ReceiveParametersContent>
        <OutArgument x:TypeArguments="local:Workflow" x:Key="workflow">[Workflow]</OutArgument>
      </p:ReceiveParametersContent>
    </p:Receive>
    <local1:InvokeActivity Activity="[ActivityXamlServices.Load(New System.IO.StringReader(Workflow.Xaml))]" sap:VirtualizedContainerService.HintSize="255,22" />
  </Sequence>
</Activity>

... che, fatta eccezione per l'uso ripetitivo di "flusso di lavoro" è piuttosto semplice. In realtà, è solo un Sequence con un Receive e [attualmente] un'usanza attività denominata InvokeActivity. Get a che in un po '.

Receive Attività accetta un tipo personalizzato,

[DataContract]
public class Workflow
{
    [DataMember]
    public string Xaml { get; set; }
}

che contiene una stringa il cui contenuto deve essere interpretato come Xaml. Si può vedere l'espressione di VB il quale trasforma quest'immagine Xaml ad un'attività e lo passa.

Ora, questo secondo bit, il InvokeActivity personalizzato è dove ho domande.

Prima domanda:

1) dato un compito arbitrario, fornito in fase di esecuzione [come sopra descritto] è possibile dare il via questa attività utilizzando le attività che nave con WF4RC, fuori dalla scatola? Sono abbastanza nuovo, e ho pensato di aver fatto un buon lavoro passa attraverso l'API e la documentazione esistente, ma può anche chiedere:)

Secondo:

2) il mio primo tentativo di attuazione di un InvokeActivity personalizzato guardato come questo

public sealed class InvokeActivity : NativeActivity
{
    private static readonly ILog _log = 
        LogManager.GetLogger (typeof (InvokeActivity));

    public InArgument<Activity> Activity { get; set; }

    public InvokeActivity ()
    {
        _log.DebugFormat ("Instantiated.");
    }

    protected override void Execute (NativeActivityContext context)
    {
        Activity activity = Activity.Get (context);

        _log.DebugFormat ("Scheduling activity [{0}]...", activity.DisplayName);

        // throws exception to lack of metadata! :(
        ActivityInstance instance = 
            context.ScheduleActivity (activity, OnComplete, OnFault);

        _log.DebugFormat (
            "Scheduled activity [{0}] with instance id [{1}].", 
            activity.DisplayName, 
            instance.Id);
    }

    protected override void CacheMetadata (NativeActivityMetadata metadata)
    {
        // how does one add InArgument<T> to metadata? not easily
        // is my first guess
        base.CacheMetadata (metadata);
    }

    // private methods

    private void OnComplete (
        NativeActivityContext context, 
        ActivityInstance instance)
    {
        _log.DebugFormat (
            "Scheduled activity [{0}] with instance id [{1}] has [{2}].",
            instance.Activity.DisplayName, 
            instance.Id, 
            instance.State);
    }

    private void OnFault (
        NativeActivityFaultContext context, 
        Exception exception, 
        ActivityInstance instance)
    {
        _log.ErrorFormat (
@"Scheduled activity [{0}] with instance id [{1}] has faulted in state [{2}] 
{3}", 
            instance.Activity.DisplayName, 
            instance.Id, 
            instance.State, 
            exception.ToStringFullStackTrace ());
    }
}

che tenta di programmare l'attività specificata nel contesto attuale. Purtroppo, però, questo non riesce. Quando si tenta di programmare detta attività, il runtime ritorna con le seguenti eccezioni

  

L'attività prevista non faceva parte di questa definizione flusso di lavoro quando i metadati veniva esaminata. L'attività problematica chiamato 'DynamicActivity' stato fornito dall'attività di nome 'InvokeActivity'.

A destra, in modo che l'Activity "dinamico" fornito in fase di esecuzione non è membro di InvokeActivitys metadati. Googled e mi sono imbattuto questo . Potrebbe non risolvere come specificare un InArgument<Activity> alla cache dei metadati, quindi la mia seconda domanda è, naturalmente, come si fa ad affrontare questo problema? E 'mal consigliato per l'uso context.ScheduleActivity (...) in questo modo?

Terza ed ultima,

3) ho optato per questo [semplice] soluzione, per il momento,

public sealed class InvokeActivity : NativeActivity
{
    private static readonly ILog _log = 
        LogManager.GetLogger (typeof (InvokeActivity));

    public InArgument<Activity> Activity { get; set; }

    public InvokeActivity ()
    {
        _log.DebugFormat ("Instantiated.");
    }

    protected override void Execute (NativeActivityContext context)
    {
        Activity activity = Activity.Get (context);

        _log.DebugFormat ("Invoking activity [{0}] ...", activity.DisplayName);

        // synchronous execution ... a little less than ideal, this
        // seems heavy handed, and not entirely semantic-equivalent
        // to what i want. i really want to invoke this runtime
        // activity as if it were one of my own, not a separate
        // process - wrong mentality?
        WorkflowInvoker.Invoke (activity);

        _log.DebugFormat ("Invoked activity [{0}].", activity.DisplayName);
    }

}

che invoca semplicemente specificato compito in modo sincrono all'interno della propria istanza di runtime thingy [uso del vernacolo WF4 è certamente discutibile]. Alla fine, vorrei attingere il monitoraggio di WF e possibilmente persistenza strutture. Così la mia terza e ultima domanda è, in termini di quello che vorrei fare [cioè kick off flussi di lavoro arbitrarie in entrata da applicazioni client] è questo il metodo preferito?

Va bene, grazie in anticipo per il vostro tempo e considerazione:)

È stato utile?

Soluzione

  

L'attività prevista non faceva parte di questa definizione flusso di lavoro quando i metadati stava essendo> trasformati. L'attività problematica chiamato 'DynamicActivity' stato fornito dall'attività> chiamato 'InvokeActivity'.

Workflow 4.0 consente solo ai bambini di pianificazione che facevano parte della struttura prima di iniziare l'esecuzione.

Questa regola probabilmente esiste perché l'albero in modo integrato è riutilizzabile per più istanze worklfow. Se esempio Un dovesse modificare l'albero mentre istanza B è ancora in esecuzione, i risultati sarebbero dare alla squadra runtime mal di testa terribili.

In pratica questo significa l'unico modo si può fare quello che vuoi con la pianificazione del bambino in modo dinamico in fase di esecuzione è quello di dare il via uno completamente nuovo flusso di lavoro (ed eventualmente attendere che per completare).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top