Hello WWF using C++/CLI






3.57/5 (7 votes)
How to build a Hello World WWF application using C++/CLI
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.
//The workflow
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)
{
//Hosting the runtime
try
{
//create an instance of workflow runtime
WorkflowRuntime^ wf = gcnew WorkflowRuntime();
//using that create an instance of Workflow1
WorkflowInstance^ workflowInstance = wf->
CreateWorkflow(Workflow1::typeid);
//Start the workflow
workflowInstance->Start();
//wait for the workflow to execute
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.