Frequently I'm involved on speaking where we present products like Dynamics NAV, Dynamics CRM, Sharepoint and all the new .NET 3.5 platform in general. One of the common aspects that I like to put in evidence is that all these products (except NAV) supports natively one of the coolest aspects of the new .NET platform: Windows Workflow (it's not a mistery that I'm a Windows Workflow lover and I like to show that with Windows Workflow you can build modular business processes).
One of the common question that often I receive is: can we extend Dynamics NAV with Windows Workflow?
First reaction: no... actually Dynamics NAV doesn't support Windows Workflow platform.
But if you think a little bit... in the past I've written three posts about how to extend Dynamics NAV with .NET functions (here, here and here). So, why not using these tecniques with Windows Workflow?
Here I want to leave a little tip (not a complete project) on how you can work with Windows Workflow and NAV.
Imagine that you're a company and your ERP is Dynamics NAV. Imagine that you have a business rule like this (it's only a sample...):
A sales order can be released if the customers meets certain requirements regarding security. The customer's security requirements are stored in an external database (for example an AS400 system or something like this). If the security check for the customer is OK, the order can be released, otherwise the order must be rejected.
On the Sales Header table in NAV you have a boolean value called "Accepted" (default=false) that indicates if the order can be emitted or not (based on the customer check). Only accepted orders can be released. How to set this boolean field?
An elegant and flexible way to solve this requirement is using Windows Workflow from Dynamics NAV.
The starting point for this solution is my post where I've explained how to write a .NET control for NAV.
Open Visual Studio and create a new Sequential Workflow Library project. Drag only a CodeActivity and call it CheckCustomer.
The CodeActivity has an ExecuteCode property where you have to assign the function that makes the Customer security check (I've called it CheckCustomerSecurity):
Your final workflow code will be something like this:
Public Class Workflow1
Inherits SequentialWorkflowActivity
Private _CustomerNo As String
Private _OutputResult As Integer
'Input value (Customer Number from NAV)
Public WriteOnly Property CustomerNumber() As String
Set(ByVal value As String)
_CustomerNo = value
End Set
End Property
'Output value from Workflow
Public ReadOnly Property OutputValue() As Boolean
Get
Return _OutputResult
End Get
End Property
Private Sub CheckCustomerSecurity(ByVal sender As System.Object, ByVal e As System.EventArgs)
'Receives the Customer Number from NAV
'Goes to the external system
'Verify if the customer is OK
'Return the result (true or false) by setting the
'boolean field on the Sales Header table in NAV
_OutputResult = True
End Sub
End Class
Compile the project and now you have the workflow DLL that you can use from NAV.
Now create a new Class Library project and add the references to the Workflow assembly previously created and to the Windows Workflow assemblies listed below:
The final code will be something like this (remember to check my previous post for details):
Imports System.Runtime.InteropServices
Imports System.Reflection
Imports System.Workflow.Runtime
Imports System.Workflow.ComponentModel
Imports System.Workflow.Activities
Imports System.Threading
Imports NAVWorkflow
Public Interface INavWorkflow
Function RunWorkflow(ByVal CustomerNo As String) As Boolean
End Interface
<ClassInterface(ClassInterfaceType.None)> _
Public Class NAVWorkflow
Implements INavWorkflow
Shared WaitHandle As New AutoResetEvent(False)
Shared _result As Boolean
Public Function RunWorkflow(ByVal CustomerNo As String) As Boolean Implements INavWorkflow.RunWorkflow
Dim workflowRuntime As New WorkflowRuntime()
Dim Parameters As Dictionary(Of String, Object) = New Dictionary(Of String, Object)
AddHandler workflowRuntime.WorkflowCompleted, AddressOf OnWorkflowCompleted
AddHandler workflowRuntime.WorkflowTerminated, AddressOf OnWorkflowTerminated
Dim workflowInstance As WorkflowInstance
'Start the workflow by passing the Customer Number
Parameters.Add("CustomerNumber", CustomerNo)
workflowInstance = workflowRuntime.CreateWorkflow(GetType(Workflow1), Parameters)
workflowInstance.Start()
WaitHandle.WaitOne()
End Function
Shared Sub OnWorkflowCompleted(ByVal sender As Object, ByVal e As WorkflowCompletedEventArgs)
_result = e.OutputParameters("OutputValue")
'MsgBox("Output parameter: {0} " & e.OutputParameters("OutputValue").ToString)
WaitHandle.Set()
End Sub
Shared Sub OnWorkflowTerminated(ByVal sender As Object, ByVal e As System.Workflow.Runtime.WorkflowTerminatedEventArgs)
End Sub
End Class
The RunWorkflow method will be called from NAV. It receives the Customer Number as input parameter, creates the Workflow Runtime and starts the workflow.
The workflow will check if the customer satisfy the business rules and updates the boolean field in the Sales Header table in NAV.
The workflow now is extremely simple: it's only a single CodeActivity. The interesting aspect is that if the business needs will change, you have to modify only the workflow itself and all the code inside NAV remains the same.
Interesting, isn't it? 