The Llamachant Framework Workflow module provides a flexible and extensible framework for defining and managing automated workflows within your DevExpress XAF application. It introduces a visual, object-driven approach to workflow configuration, allowing administrators or power users to define workflow definitions, triggers, conditions, and actions using an intuitive UI.
Each workflow definition can be associated with a business object type and evaluated against custom criteria or time-based schedules. Triggers can launch workflows in response to changes (e.g., property updates, object creation), and actions support executing predefined logic such as sending emails, updating fields, or invoking custom code.
This module is designed to be integrated directly into your XAF application, enabling administrators to configure workflows at runtime without requiring code changes or redeployments.
If you're upgrading from the legacy modules and you utilize ModuleInfo as the CheckCompatibilityType within your application, you need to update the module name in the ModuleInfo table. Otherwise you application may hang after login.
UPDATE ModuleInfo SET Name = 'LlamachantFrameworkWorkflowModuleXpo' WHERE Name = 'LlamachantFrameworkWorkflowModuleXPO'
The Llamachant Framework Workflow module provides a flexible and extensible framework for defining and managing automated workflows within your DevExpress XAF application. It introduces a visual, object-driven approach to workflow configuration, allowing administrators or power users to define workflow definitions, triggers, conditions, and actions using an intuitive UI.
Each workflow definition can be associated with a business object type and evaluated against custom criteria or time-based schedules. Triggers can launch workflows in response to changes (e.g., property updates, object creation), and actions support executing predefined logic such as sending emails, updating fields, or invoking custom code.
This module is designed to be integrated directly into your XAF application, enabling administrators to configure workflows at runtime without requiring code changes or redeployments.
If you're upgrading from the legacy modules and you utilize ModuleInfo as the CheckCompatibilityType within your application, you need to update the module name in the ModuleInfo table. Otherwise you application may hang after login.
UPDATE ModuleInfo SET Name = 'LlamachantFrameworkWorkflowModuleXpo' WHERE Name = 'LlamachantFrameworkWorkflowModuleXPO'
Install the relevant ORM-specific module:
Install-Package 'Llamachant.ExpressApp.Workflow.Xpo'
OR
Install-Package 'Llamachant.ExpressApp.Workflow.EF'
Register the relevant ORM-specific module (either Xpo or EF Core):
public override void Setup(XafApplication application) {
base.Setup(application);
// Xpo:
this.RequiredModuleTypes.Add(typeof(LlamachantFrameworkWorkflowModuleXPO));
// EF Core:
this.RequiredModuleTypes.Add(typeof(LlamachantFrameworkWorkflowModuleEF));
}
OR
services.AddXaf(Configuration, builder => {
builder.UseApplication<ExpressAppBlazorApplication>();
builder.Modules
// Xpo:
.AddLlamachantFrameworkWorkflowModuleXPO();
// EF Core:
.AddLlamachantFrameworkWorkflowModuleEF();
});
If using EF Core, add the following DbSet entries in your DbContext:
public class MySolutionEFCoreDbContext : DbContext {
public DbSet<WorkflowDefinition> WorkflowDefinition { get; set; }
public DbSet<WorkflowInstance> WorkflowInstance { get; set; }
public DbSet<WorkflowEmailSettings> WorkflowEmailSettings { get; set; }
public DbSet<WorkflowEmailTemplate> WorkflowEmailTemplates { get; set; }
}
If you receive the following error message, ensure you have the DevExpress.ExpressApp.ReportsV2 module registered in your Startup class with .AddReports()
System.InvalidOperationException: No service for type 'DevExpress.ExpressApp.ReportsV2.IReportDataSourceHelper' has been registered.
Workflow Service Engine Required – Create a service, application, or logic that leverages the Workflow Service Engine for execution. Find out more about the Workflow Service Engine Here.
Install the relevant ORM-specific module:
Install-Package 'Llamachant.ExpressApp.Workflow.Xpo'
OR
Install-Package 'Llamachant.ExpressApp.Workflow.EF'
Register the relevant ORM-specific module (either Xpo or EF Core):
public override void Setup(XafApplication application) {
base.Setup(application);
// Xpo:
this.RequiredModuleTypes.Add(typeof(LlamachantFrameworkWorkflowModuleXPO));
// EF Core:
this.RequiredModuleTypes.Add(typeof(LlamachantFrameworkWorkflowModuleEF));
}
OR
services.AddXaf(Configuration, builder => {
builder.UseApplication<ExpressAppBlazorApplication>();
builder.Modules
// Xpo:
.AddLlamachantFrameworkWorkflowModuleXPO();
// EF Core:
.AddLlamachantFrameworkWorkflowModuleEF();
});
If using EF Core, add the following DbSet entries in your DbContext:
public class MySolutionEFCoreDbContext : DbContext {
public DbSet<WorkflowDefinition> WorkflowDefinition { get; set; }
public DbSet<WorkflowInstance> WorkflowInstance { get; set; }
public DbSet<WorkflowEmailSettings> WorkflowEmailSettings { get; set; }
public DbSet<WorkflowEmailTemplate> WorkflowEmailTemplates { get; set; }
}
If you receive the following error message, ensure you have the DevExpress.ExpressApp.ReportsV2 module registered in your Startup class with .AddReports()
System.InvalidOperationException: No service for type 'DevExpress.ExpressApp.ReportsV2.IReportDataSourceHelper' has been registered.
Workflow Service Engine Required – Create a service, application, or logic that leverages the Workflow Service Engine for execution. Find out more about the Workflow Service Engine Here.
Create email templates and embed object data directly into HTML-based messages.
Use expressions like {{FirstName}} or {{Address.State.Name}}.
For double brace support, configure TemplateFormattingFactory.SetDefaultFormattingType.
Carefully configure frequency, conditions, and actions for your workflows to avoid errors like repeated execution or accidental deletion.
ActionName and attach it to a button or action in the UI.Extend IWorkflowEmailService and register your service in the module setup.
Register your service in WorkflowModule.EmailServiceType and related types.
public override void Setup(XafApplication application) {
base.Setup(application);
application.SetupComplete += Application_SetupComplete;
}
private void Application_SetupComplete(object sender, EventArgs e) {
var application = (XafApplication)sender;
var module = LlamachantFramework.Workflow.WorkflowModule.FindModule(application.Modules);
module.EmailServiceType = typeof(DummyEmailService);
module.EmailSettingsType = typeof(DummyEmailSettings);
module.WorkflowDefinitionType = typeof(MyWorkflowDefinition);
module.WorkflowInstanceType = typeof(MyWorkflowInstance);
}
public class DummyEmailService : IWorkflowEmailService {
public byte[] GetExportedReport(...) => new byte[0];
public void SendEmail(...) { }
}
public class ExtendedEmailService : WorkflowEmailService {
public override void SendEmail(...) {
base.SendEmail(...);
}
}
Create email templates and embed object data directly into HTML-based messages.
Use expressions like {{FirstName}} or {{Address.State.Name}}.
For double brace support, configure TemplateFormattingFactory.SetDefaultFormattingType.
Carefully configure frequency, conditions, and actions for your workflows to avoid errors like repeated execution or accidental deletion.
ActionName and attach it to a button or action in the UI.Extend IWorkflowEmailService and register your service in the module setup.
Register your service in WorkflowModule.EmailServiceType and related types.
public override void Setup(XafApplication application) {
base.Setup(application);
application.SetupComplete += Application_SetupComplete;
}
private void Application_SetupComplete(object sender, EventArgs e) {
var application = (XafApplication)sender;
var module = LlamachantFramework.Workflow.WorkflowModule.FindModule(application.Modules);
module.EmailServiceType = typeof(DummyEmailService);
module.EmailSettingsType = typeof(DummyEmailSettings);
module.WorkflowDefinitionType = typeof(MyWorkflowDefinition);
module.WorkflowInstanceType = typeof(MyWorkflowInstance);
}
public class DummyEmailService : IWorkflowEmailService {
public byte[] GetExportedReport(...) => new byte[0];
public void SendEmail(...) { }
}
public class ExtendedEmailService : WorkflowEmailService {
public override void SendEmail(...) {
base.SendEmail(...);
}
}
This workflow automatically sends a Daily Work Summary email to the management team each morning at 8am, including an attached Summary.pdf report. The email helps ensure all employees have properly logged their hours from the previous day, providing management with timely visibility into workforce attendance and productivity.
| Setting | Value |
|---|---|
| Name | Daily Work Summary |
| Frequency | Daily |
| Interval | 1 |
| Next Run Date | Tomorrow, 8am |
| Send An Email | True |
| Attach A Report | True |
| Email Template | Daily Work Summary Email |
| Email Addresses | managers@..... |
| Report | Daily Work Summary Report |
| Report Name | Summary |
| Attachment Type |
This workflow automatically sends a Daily Work Summary email to the management team each morning at 8am, including an attached Summary.pdf report. The email helps ensure all employees have properly logged their hours from the previous day, providing management with timely visibility into workforce attendance and productivity.
| Setting | Value |
|---|---|
| Name | Daily Work Summary |
| Frequency | Daily |
| Interval | 1 |
| Next Run Date | Tomorrow, 8am |
| Send An Email | True |
| Attach A Report | True |
| Email Template | Daily Work Summary Email |
| Email Addresses | managers@..... |
| Report | Daily Work Summary Report |
| Report Name | Summary |
| Attachment Type |
| Setting | Value |
|---|---|
| Name | Process New Clients |
| Frequency | One time (Per record) |
| Run this workflow against individual objects | True |
| Target Object Type | Client |
| Criteria | [Category] = 'Normal' |
| Invoke a Method | True |
| Method Name | SetupClientAccount |
public class Client : BaseObject
{
public void SetupClientAccount()
{
//Do anything you need in order to set up the client account here
}
}
| Setting | Value |
|---|---|
| Name | Process New Clients |
| Frequency | One time (Per record) |
| Run this workflow against individual objects | True |
| Target Object Type | Client |
| Criteria | [Category] = 'Normal' |
| Invoke a Method | True |
| Method Name | SetupClientAccount |
public class Client : BaseObject
{
public void SetupClientAccount()
{
//Do anything you need in order to set up the client account here
}
}
This workflow automatically sends a Weekly Billable Hours Summary report to clients who had time entries during the previous week. The report provides clients with a summary of work progress and associated costs, helping maintain transparency and set expectations for monthly billing cycles.
| Setting | Value |
|---|---|
| Name | Weekly Billable Hours Summary |
| Frequency | Weekly |
| Interval | 1 |
| Next Run Date | Monday, 9am |
| Run this workflow against individual objects | True |
| Target Object Type | Client |
| Criteria | [Billable Hours][[Invoice] Is Null And [Start On] >= AddDays(LocalDateTimeToday(), -7)] (User has billable hours in the last 7 days that are not invoiced) |
| Send An Email | True |
| Attach A Report | True |
| Email Template | Weekly Billable Hours Summary Email |
| Email Property Path | [EmailAddress] |
| Report | Weekly Billable Hours Summary Report |
| Report Name | Weekly Billable Hours Summary |
| Attachment Type |
This workflow automatically sends a Weekly Billable Hours Summary report to clients who had time entries during the previous week. The report provides clients with a summary of work progress and associated costs, helping maintain transparency and set expectations for monthly billing cycles.
| Setting | Value |
|---|---|
| Name | Weekly Billable Hours Summary |
| Frequency | Weekly |
| Interval | 1 |
| Next Run Date | Monday, 9am |
| Run this workflow against individual objects | True |
| Target Object Type | Client |
| Criteria | [Billable Hours][[Invoice] Is Null And [Start On] >= AddDays(LocalDateTimeToday(), -7)] (User has billable hours in the last 7 days that are not invoiced) |
| Send An Email | True |
| Attach A Report | True |
| Email Template | Weekly Billable Hours Summary Email |
| Email Property Path | [EmailAddress] |
| Report | Weekly Billable Hours Summary Report |
| Report Name | Weekly Billable Hours Summary |
| Attachment Type |