1. Home
  2. Docs
  3. Llamachant Framework Modules
  4. Additional Modules
  5. Workflow Service Engine

Workflow Service Engine

The Workflow Service Engine is used to process workflow definitions created by our LlamachantFramework.Workflow module.  The engine allows you to embed the processing logic into any application. We suggest one of the following:

  • Windows Service
  • Azure Function (Timer Based)
  • Console Application that is invoked by Task Scheduler

Getting Started

  1. Install the LlamachantFramework.Workflow.Service from NuGet into your solution
  2. Create an instance of your XAF Application
  3. Initialize the WorkflowService.Instance
  4. Configure your custom Email Service (Optional)
  5. Process the workflows

Sample Azure Function (Using XAF Blazor Application)

				
					using DevExpress.ExpressApp;
using DevExpress.ExpressApp.AspNetCore.DesignTime;
using DevExpress.ExpressApp.Security;
using LlamachantFramework.Workflow.BusinessObjects;
using LlamachantFramework.Workflow.Service;
using LlamachantFramework.Workflow.Utils;

public class RunWorkflowFunction
{
    static MyBlazorApplication app;
    static IConfigurationRoot config;

    [FunctionName("RunWorkflowFunction")]
    public void Run([TimerTrigger("0 * * * * *")]TimerInfo myTimer, ILogger log, ExecutionContext context)
    {
        DevExpress.Utils.AzureCompatibility.Enable = true;

        try
        {
            log.LogInformation("*** Function is starting ***");

            if (app == null)
            {
                log.LogInformation("Application does not exist. Creating application.");
                config = new ConfigurationBuilder().SetBasePath(context.FunctionAppDirectory)
#if DEBUG
                    .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
#endif
                    .AddEnvironmentVariables().Build();

                DevExpress.ExpressApp.FrameworkSettings.DefaultSettingsCompatibilityMode = DevExpress.ExpressApp.FrameworkSettingsCompatibilityMode.Latest;


                IHostBuilder hostBuilder = Program.CreateHostBuilder(new string[0]);

                app = (MyBlazorApplication)DesignTimeApplicationFactoryHelper.Create(hostBuilder);
                app.ConnectionString = config.GetConnectionString("ConnectionString");
                app.CheckCompatibilityType = CheckCompatibilityType.DatabaseSchema;
                app.DatabaseUpdateMode = DatabaseUpdateMode.Never;
                app.Setup();

                log.LogInformation("Application created and setup complete.");                   

				TemplateFormattingFactory.SetDefaultFormattingType(TemplateFormattingFactory.TemplateFormattingType.DoubleBrace);
                //WorkflowService.Instance.EmailService = ...; //Set custom email service here if desired
                WorkflowService.Instance.TimeZone = TimeZoneInfo.FindSystemTimeZoneById(config.GetValue<string>("WorkflowTimezone"));
            }

            if (!app.GetSecurityStrategy().IsAuthenticated)
            {
                log.LogInformation("Authenticating Workflow User");
                IObjectSpace space = app.ObjectSpaceProvider.CreateUpdatingObjectSpace(false);
                AuthenticationStandardLogonParameters p = (AuthenticationStandardLogonParameters)app.Security.LogonParameters;
                p.UserName = config.GetValue<string>("WorkflowUserName");
                p.Password = config.GetValue<string>("WorkflowPassword");

                app.GetSecurityStrategy().Logon(space);
                log.LogInformation("Workflow User Authenticated Successfully.");
            }

			if (app.GetSecurityStrategy().IsAuthenticated)
			{
				log.LogInformation("Workfow Service is Initializing");
				WorkflowService.Instance.Initialize(app, logger);
				log.LogInformation("Workfow Service is Running");
				WorkflowService.Instance.RunWorkflow();
			}

            log.LogInformation("*** Function is ending ***");
        }
        catch (Exception ex)
        {
            log.LogInformation("******** Service Crash ********");
            log.LogError(ex, "");
        }
    }
}
				
			

Sample Windows Service

				
					public partial class MyWorkflowService : ServiceBase
    {
        //You can utilize the built in WorkflowQueueController to handle timing for you
        WorkflowQueueController queue = new WorkflowQueueController();

        public MyWorkflowService()
        {
            InitializeComponent();

            Tracing.Initialize();
            MyWindowsFormsApplication app = new MyWindowsFormsApplication();
            app.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
            app.SplashScreen = null;
            app.Setup();

            IObjectSpace space = app.ObjectSpaceProvider.CreateUpdatingObjectSpace(false);
            AuthenticationStandardLogonParameters p = (AuthenticationStandardLogonParameters)app.Security.LogonParameters;
            p.UserName = "Admin";

            app.GetSecurityStrategy().Logon(space);

            WorkflowService.Instance.Initialize(app, new FileSystemLogger(@"C:\Logs\"));
            //Set this to your custom IWorkflowEmailService if necessary
            //WorkflowService.Instance.EmailService = new DummyEmailService();
        }

        protected override void OnStart(string[] args)
        {
            //Set the number of seconds between checks for new workflows (60 seconds recommended)
            queue.SetInterval(60); 
            queue.Start();
        }

        protected override void OnStop()
        {
            queue.Stop();
        }
    }
				
			

Sample Console Application

				
					public class MyConsoleApp
    {
        public static void Main(string[] args)
        {
            Tracing.Initialize();
            LlamaFrameworkTestMyWindowsFormsApplication app = new MyWindowsFormsApplication();
            app.ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
            app.SplashScreen = null;
            app.Setup();

            IObjectSpace space = app.ObjectSpaceProvider.CreateUpdatingObjectSpace(false);
            AuthenticationStandardLogonParameters p = (AuthenticationStandardLogonParameters)app.Security.LogonParameters;
            p.UserName = "Admin";

            app.GetSecurityStrategy().Logon(space);

            WorkflowService.Instance.Initialize(app, new FileSystemLogger(@"C:\Logs\"));
            //Set this to your custom IWorkflowEmailService if necessary
            //WorkflowService.Instance.EmailService = new DummyEmailService();

            WorkflowService.Instance.RunWorkflow();
        }
    }
				
			

Managing Workflow Definition Dates

Handle the ProgressWorkflowDefinitionDate event in the WorkflowService.Instance to push the NextRunDate field out further. This is useful if you want to skip holidays or weekends.

				
					WorkflowService.Instance.ProgressWorkflowDefinitionDate += (s, args) =>
{
    while(e.NextRunDate.DayOfWeek == DayOfWeek.Saturday || e.NextRunDate.DayOfWeek== DayOfWeek.Sunday)
                e.NextRunDate = e.NextRunDate.AddDays(1);
};
				
			

Calculate if workflow processing is required

				
					WorkflowService.Instance.CalculateNeedsProcessing += (s, args) =>
{
    bool blankemail = e.ObjectToProcess is Client c && String.IsNullOrEmpty(c.EmailAddress) && e.WorkflowDefinition.Name == "My Workflow Definition";
    
    e.Process = !blankemail;
};
				
			
Was this article helpful to you? Yes 2 No 1

How can we help?