Hi, I have a question about making a dynamic interface to workflows. I have searched thru the forums, but can't find any similarities with my problem, so I post it here. If I mistakenly missed another similar posting, please do direct me to that post.
The background first. I'm trying to separate the workflow from the application that I'm developing. Let's call the application "AppX". AppX has a lot of modules, and requires multiple number of workflows for approval processes. So, I have to create several workflows in WF. In the end, I will have AppX and several workflows. All workflows are State Machine workflow, which is the most "matched" model to approval process.
Since I'm trying to separate AppX from the workflow, I'm building an interface between AppX and WF; let's call it AppWFInterface. So if a screen in AppX wants to start a workflow instance, all it have to do is call AppWFInterface. If a screen needs to change a state of a particulare instance, it will only need to call AppWFInterface. And so on.
Now, since I'm quite new to WF, I looked at the tutorial (from MSDN) and from the SDK samples, especially for State Machine workflow. However, I immediately encounter several problems.
1. In the tutorial and samples, I found that upon building the State Machine workflow, I also need to define (and implement) Local Services, which list down all events that will be sent to the workflow. The problem is, this list of events need to be created during development, as part of the Local Services coding. In my case, instead of "hardcoding" the events, I want them to be listed in DB (or config), where AppWFInterface can do mapping as necessary. Is it possible to list down the events without hardcoing it in to the Local Services? Do I really need Local Services?
2. In the tutorial, the application call the workflow object directly. Meanwhile, in my application, I need to refer to the workflow dynamically, getting the workflow object name from configuration file or DB. Is it possible to achieve this?
3. I noticed that State Machine workflow are event based, using events to control the change between states. The application send the events using async method. However, in my case, AppX need to know immediately whether the approval process succeded or not, because some rules in the workflow itself can make the approval process failed. So, sync method is more preferred. Is it possible?
Thanks and regards.
- irving
| | irving at irvingevajoan | I think I found the answer for my #2 question. I found it from the OrderingStateMachine sample from WFSamples. Here is the snipet.
// NOTE: "Late-binding to the OrderWorkflows" assembly so we // ...can easily copy this exe and project into another soluton
// Load the OrderWorkflows assembly Assembly orderWorkflowsAssembly = Assembly.Load("OrderWorkflows");
// Get a reference to the System.Type for the OrderWorkflows.Workflow1 Type workflowType = orderWorkflowsAssembly.GetType("Microsoft.Samples.Workflow.OrderApplication.SampleWorkflow"); | | irving at irvingevajoan | Question 1:
You don't really need local communication services. You can bypass that mechanism by using the Workflow Queueing mechanism directly. The queueing mechanism is explained in the chapter 3 of Essential Workflow Foundation, available online here:
http://wf.netfx3.com/files/folders/books/default.aspx
Although I don't quite understand your problem, that sample chapter should give you interesting ideas.
Question 3:
Isn't that basically just a new communication need? Why don't you just call an external method from the workflow to notify the host application whenever your approval process fails?
regards, Jussi | | Jussi Isotupa | For #1, thanks for the link, I'll read the chapter first and make my response to this thread.
For #3, the question is not about "how" to update the host, but rather "when" can I update the host. The basic problem is this: a user using the host application will click on an approval button, and will expect to know whether the approval process succeed or failed. However, since the event raised by the host is async in nature, the host app will continue its process even though the workflow is still processing the approval event. In the end, when the workflow is done, it can call an external method to notify the host, or maybe to update a DB in the host app to update that the status of the approval process is either success or not. Using this method, the user will have to query (or poll) the host app to know the last status of the approval process.
Unless, I can make the host "wait" for an event from the workflow. Is this what you're suggesting?
Regards, Irving
| | irving at irvingevajoan | #3: Ok, I slightly misunderstood the question. Does the workflow end when the approval fails or succeeds? If it does, you can implement the waiting behavior in similar fashion to program.cs file generated by Console Workflow Application template in Visual Studio, see below.
But you defininately should add a timeout to the WaitOne call to prevent the UI from blocking too long. From user experience perspective, it's not a good idea to make the UI thread wait.
If you need to report the approval status while the workflow is still executing, you can use local communication services and signal the wait handler from your local communication service.
Example, see the bolded lines.
class WorkflowApplication { static AutoResetEvent waitHandle = new AutoResetEvent(false); | | Jussi Isotupa | Thanks for the reply. I've seen the code in the Console app before. But like you mentioned, that code is to wait for the workflow to finish or terminated, which is good for sequential workflow but not necessarily helpful for state machines.
What I'm trying to achieve is for the workflow to send back a signal (or event) back to the host to tell the host that the workflow has finished processing the external event. The host will need to know whether the process is successful, and what is the new "current state". I assume that these 2 data can be sent along with the signal, or I can put it as a property in the workflow which the host can access.
I'm not really good with events or signals coding. Can you be kind enough to write a rough code for me? Or maybe not necessarily a code, just the steps. What method (and object) the workflow need to call to "send" the signal? What will the Local Service need to do? What will the host need to do?
Thanks a lot.
- irving
| | irving at irvingevajoan | You should be able to listen for the workflow idled event which will let you know that it is done processing. Then you can use the StateMachineworkflowInstance class to query for info on the workflow.
Or, in your workflow, you can use the CallExternalMethod activity to call out to your host with updated information.
Or, you can use a custom tracking service that tracks the SetState calls and reports to your host what the current state is.
Matt
See What You Can Learn -- http://www.pluralsight.com/courses/IntroducingWF.aspx | | Matt Milner - Pluralsight | Okay, based on Matt's post, I coded the solution this way.
First, in the host, I define a private event.
private AutoResetEvent waitHandle;
Then, before calling the LocalService method which will send the event to WF, I create an instance of the waitHandle and use it to wait.
private void Approve_Click(object sender, EventArgs e) { waitHandle = new AutoResetEvent(false); // Raise an Approve event using the Workflow Service workflowService.RaiseApproveEvent("", workflowInstanceId);
Debug.Print("End Approve Click");
waitHandle.WaitOne();
Debug.Print("End wait"); }
Of course, I already put a handler for the WorkflowIdled event.
private void Runtime_WorkflowIdled(object sender, WorkflowEventArgs e) { // Get the underlying WorkflowInstance StateMachineWorkflowInstance stateMachineInstance = new StateMachineWorkflowInstance(workflowRuntime, e.WorkflowInstance.InstanceId);
// Update the Workflow State & Status stateMachineInstance.CurrentState.Name, "Running"); Debug.Print("Workflow Instance ID: {0}, Current State: {1}, Current Status: {2}", e.WorkflowInstance.InstanceId.ToString(), stateMachineInstance.CurrentState.Name, "Running");
if (waitHandle != null) { waitHandle.Set(); } }
I have to put the null check because WorkflowIdled also got called during the initial creation of the workflow instance.
Now, I managed to make it "synchronous". But, the questions remains: is this the correct design pattern? I mean, I'm forcing StateMachine WF to become a synchronous instead of asynchronous. Is this the right way, the right design?
Thanks.
| | irving at irvingevajoan |
|