therefore, I have this requirement to begin work provided to me at runtime. To facilitate this, I created a WorkflowService that takes actions like Xaml, moisturizes them and repels them.
That sounds easy enough ...
... this is my Xaml WorkflowService
<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>
... which, with the exception of reusing "Workflow", is pretty straight forward. In fact, it's just Sequencewith Receiveand [currently] customizable activity called InvokeActivity. Come to this a bit.
Receive The action takes a custom type,
[DataContract]
public class Workflow
{
[DataMember]
public string Xaml { get; set; }
}
which contains a string whose contents should be interpreted as Xaml. You can see the VB expression, which then converts this Xaml to Activity and passes it.
, InvokeActivity, .
:
1), , [ ], , WF4RC, ? , API , :)
-:
2) InvokeActivity :
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);
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)
{
base.CacheMetadata (metadata);
}
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 ());
}
}
. , . , .
, . " " "InvokeActivity".
, "" , , InvokeActivity. Googled this. , InArgument<Activity> , , , , ? context.ScheduleActivity (...) ?
,
3) [ ] ,
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);
WorkflowInvoker.Invoke (activity);
_log.DebugFormat ("Invoked activity [{0}].", activity.DisplayName);
}
}
[ WF4-, , ]. , WF- , , . , : , (.. ), ?
, :)