Introduction
Windows Workflow Foundation represents one of the Key technologies
in the .NET framework version 3.0(Formerly known as WinFX).
There are lot of samples in WWF using languages such as C#, VB.NET etc.
Being a C++ fan, I tried to build a sample using C++/CLI. There is no
support for building applications in C++/CLI using Visual Studio
Extensions for WWF.Project types appear only under Visual C#. So for
building the application you have to do almost everything by hand.
These are the important points to remember when developing WWF
applications under C++/CLI.
- Lack of Project types to quickly build a template
- No support for debugging XOML etc.
- Lack of Design time support for workflow authoring.
If you are willing to live up with these things you can do
development of WWF applications under C++/CLI.
There could be some scenarios where it might be beneficial to do
Development in C++/CLI.
You have some existing code base in C++ which you would like to
workflow enable. You can create a C++/CLI Activity Library and plug it
into the Workflow runtime. Inside the Activity library you can use the
IJW feature of C++/CLI to call your native code. Secondly C++/CLI might
emit faster optimized IL code which you could consider for even a
Workflow hosting environment.
Pre-requisites for starting workflow development in WWF are .NET 3.0
framework
Windows Workflow Foundation Runtime Components Visual Studio 2005
Extensions for WWF.
Let us discuss some key concepts of developing workflow applications
before we delve into code.
What is WWF?
WWF can be thought of consisting of tools,engine and a model for
building workflow applications. It is not a end user product, it is
more of a software developer tool.
This infact is the core difference between BizTalk Server and WWF.
Biztalk is a server product while WWF is a runtime which developers
need
to leverage on.
There are many industry accepted standards behind workflow frameworks.
WFMC is one such standard(www.wfmc.org). BPEL is another. Windows
workflow foundation model
is a standard which you have to live upto if you are serious about
workflow development under WWF. In WWF, a workflow definition consists
of Activities.
There are two main types of workflows in WWF.
- Sequential Workflows used for well-defined, business processes
- State Machine used for human workflows
Workflows can be long running. Support for this comes in the form of
persistance service etc. Many aspects of the Runtime can be customized
by developing our own custom services. For e.g if you don't like the
persistance service and you would like to write the state to a Access
mdb, then you can write a custom Persistance Service and plug it into
the Workflow runtime.
Once you have decided on the type of workflow for a scenario,
the next point is developing activities which constitute the workflow.
There are out of the box activities and you can develop custom
activities.
Activities can be single or composite. A composite activity itself
comprises of individual activities.
A workflow can be thought of as a composite activity. This allows you
to call a workflow within a workflow. This could happen if you want to
call a Financial process within a Leave workflow.
A real benefit of developing Workflows to model processes in your buisnesses is simplifying complex looking
scenarios by visually modelling them and therby providing the ability to extend them.By making it declarative and
expliict, a Workflow definition creates the correct abstraction for the scenario.
Constructing a Sequential Workflow
Let us construct a simple workflow consisting of just two
activities. Thw workflow model was constructed with the C# Sequential
Workflow Console application project type.
In WWF, you can create workflows either using markup or imperatively
using any CLR language.
The markup specification is similar to XAML in WPF, and for the
Designer to distinguish that it is in fact a Workflow definition rather
than a graphics application the extension is XOML.
Studying the project and understanding how the workflow runtime was
invoked helped me to construct a project using C++/CLI.
If you construct a Sequential Workflow console application project in
C#. There are two main classes generated. One is the workflow class
which is derived from SequentialWorkflowActivity. When you drag and
drop CodeActivities from the toolbox member variables are created in
this class of type CodeActivity.
Secondly the events of Actvities are hooked so that when the runtime is
used to start the workflow and activities are triggered, the sink
functions are invoked.
The second aspect is the Shell which invokes the workflow runtime and
creates an instance of the workflow which we constructed using markup.
The shell also starts the workflow instance thus created.
Create a C++/CLI console application called WorkflowApp.CPP. You would
be provided with a main function as expected. The first part is
constructing the Workflow class.
ref class Workflow1: SequentialWorkflowActivity
{
public:
Workflow1()
{
codeActivity1 = gcnew CodeActivity();
codeActivity2 = gcnew CodeActivity();
this->Activities->Add(codeActivity1);
this->Activities->Add(codeActivity2);
codeActivity1->ExecuteCode += gcnew EventHandler(
this, &Workflow1::codeActivity1_ExecuteCode);
codeActivity2->ExecuteCode += gcnew EventHandler(
this, &Workflow1::codeActivity2_ExecuteCode);
}
private:
void codeActivity1_ExecuteCode(System::Object^ sender,
EventArgs^ e)
{
Console::Write("Hello");
}
void codeActivity2_ExecuteCode(System::Object^ sender,
EventArgs^ e)
{
Console::WriteLine("World");
}
CodeActivity^ codeActivity1;
CodeActivity^ codeActivity2;
};
The code is self explanatory. The workflow class consists of two
activities of type CodeActivity. In the ctor we create them and hook
the ExecuteCode event onto sink functions. The workflow class is
derived from SequentialWorkflowActivity.
Now comes the main function.
int main(array<System::String ^> ^args)
{
try
{
WorkflowRuntime^ wf = gcnew WorkflowRuntime();
WorkflowInstance^ workflowInstance = wf->
CreateWorkflow(Workflow1::typeid);
workflowInstance->Start();
Console::ReadLine();
}
catch(WorkflowValidationFailedException^ ex)
{
String^ str = ex->Message;
Console::WriteLine(str);
}
return 0;
}
The next step would be to create an instance of the workflow and
start it. For this we have to create an instance of the Workflow
runtime first. You need to create the runtime instance only once during
the application lifetime.
Next we use the CreateWorkflow function of the workflow runtime to
create an instance of our workflow.
The CreateWorkflow function is heavily overloaded.You can create it
from a type , you can create it from a XML markup which is in the XAML
format etc. Here we use the typeid operator to get the type associated
with the workflow that we have defined.
When you run this, the workflow is started and each activity is executed one by one and you get the expected output.
Notice the use of Console::ReadLine towards the end which results is a wait so that the workflow can finish execution.
A more serious implementation would be to use a Event object and using one of the wait functions.
System::Threading::AutoResetEvent^ waitHandle =
gcnew System::Threading::AutoResetEvent(false);
...
workflowInstance->Start();
waitHandle->WaitOne();
Developing a Custom Activity
Next we will see how to develop a Custom activity. For this, all you
have to do is to write a class derived from Activity and override the
Execute virtual fuction. The code is simple and straightforward.
ref class CustomActivity : System::Workflow::ComponentModel
::Activity
{
protected:
virtual ActivityExecutionStatus Execute(
ActivityExecutionContext^ executionContext) override
{
Console::WriteLine("Custom activity executed");
return ActivityExecutionStatus::Closed;
}
};
Notice the return type.It is of type ActivityExecutionStatus . If
everything is as expected we return ActivityExecutionStatus::Closed.
But if for some reason we want to stop the workflow we can provide a
return status ActivityExecutionStatus::Canceling to stop the workflow
from further execution.
In order to plug in the custom activity all you have to do is
to add it into the workflow class. You need not hook the event sink.
codeActivity3 = gcnew CustomActivity();
this->Activities->Add(codeActivity3);
Conclusion
As you can observe developing in C++/CLI is a little difficult as you lack support from the IDE and template code generators.
However if you understand how the pieces fit togther you can develop workflow applications in any CLR compliant language.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.