Part 3 of Building Workflow Driven .NET Applications with Elsa 2
Executing workflows from JSON files & Workflow Providers
In the previous part, we setup a solution with an ASP.NET Core web application and configured it to be an Elsa server.
We’ve seen that we can design workflows with Elsa Studio that are then somehow available to our app.
But how and where are these workflows stored?
In this part, we will learn about workflow providers.
Workflow Providers
Elsa provides an interface called IWorkflowProvider
and its up to the various implementations of this interface to provide workflow blueprints to the workflow registry. Let’s go over these definitions first.
Workflow Blueprint
The workflow blueprint is an in-memory representation of the workflow to execute. It stores a list of activities and their connections. The workflow engine uses this information to determine what activity to execute next once the current activity finished execution.
Workflow Registry
The workflow registry is a service that is used to list all available workflows. It is used by various other services such as the trigger indexer to index start activities that represent workflow triggers, and it is used by applications to select workflows to execute.
The workflow registry queries all workflow providers registered with the service container to build up a complete list of available workflow blueprints.
Let’s go over the built-in workflow providers next.
Built-in Workflow Providers
The Elsa Core package provides the following workflow providers out of the box:
- Programmatic Workflow Provider
- Database Workflow Provider
- Blob Storage Workflow Provider
Programmatic Workflow Provider
This provider enumerates all workflows that are written using the Workflow Builder API. These are regular C# classes that implement the IWorkflow
interface.
For example, take the following workflow:
public class HelloWorld : IWorkflow
{
public void Build(IWorkflowBuilder builder)
{
builder.WriteLine("Hello World!");
}
}
To make this workflow available, it needs to be registered with Elsa:
services.AddElsa(elsa => elsa.AddWorkflow<HelloWorld>);
Now, the ProgrammaticWorkflowProvider
will know about this workflow and be able to yield a workflow blueprint from it.
Database Workflow Provider
This provider enumerates all workflows as stored in the database. These workflows are stored in a JSON format and are ultimately de-serialized into workflow blueprints.
It is this provider that we saw at play in the previous part. Elsa Studio posts workflow definitions to some Elsa API endpoint, which stores them into the configured database.
Blob Storage Workflow Provider
This provider is similar to the Database workflow provider, but instead of reading workflows from a database, it reads them from JSON files through the IBlobStorage
abstraction provided by Storage.NET.
Storage.NET can be configured with a myriad of storage providers, such as local directories, Azure Blob Storage, FTP servers, and much more.
By default, Elsa configures an in-memory blob storage provider. But in this post, we will see how to configure it with a local directory so that we can store workflows as JSON files local to our application.
Why workflows as local JSON files?
There are a variety of reasons why you might consider storing workflows as part of your application instead of a database. One such reason might be to take advantage of versioning through git. Another reason might be to have complete control over when new logic gets deployed to your production environments. After all, workflows too are ultimately application code. Depending on the nature of your application, you may or may not find it desirable to be able to change application logic on the fly.
In the end, it’s all about having options.
Using Workflows as JSON Files
We created a simple Hello World workflow in the previous part and now understand that this workflow is stored in a database of our application.
Let’s see how we can serve this workflow from a local JSON file next. Here’s what we will do:
- Export the workflow from Elsa Studio as a JSON file.
- Store the exported JSON file in a sub directory of our
DocumentManagement.Workflows
project. - Configure the
BlobStorageWorkflowProvider
to read workflow files from the sub directory.
Export the workflow from Elsa Studio
If you don’t already have Elsa Studio running, do so now by running the following command:
docker run -t -i -e ELSA__SERVER__BASEADDRESS='http://localhost:5000' -p 14000:80 elsaworkflows/elsa-dashboard:latest
This will start the Elsa Studio ASP.NET application on port 14000, configured to consume Elsa Server API endpoints exposed by DocumentManagement.Web
running at http://localhost:5000
.
Next, go to the Workflow Definitions screen and either edit the Hello World workflow or create a new one as outlined in the previous part. This will take you to the workflow definition editor screen.
From this screen, you can export your workflow by clicking the little arrow pointing downwards that is part of the Publish button:
Click the Export menu item. This will export the current workflow as a JSON file and by default will be downloaded to your Downloads folder (on Windows).
The contents of the exported file looks something like this:
Copy the workflow to DocumentManagement.Workflows
Copy the JSON file and paste it into a new folder of the DocumentManagent.Workflows
project. Name this folder Workflows
.
To make sure this file gets copied to the build output directory, change its CopyToOutputDirectory
from None
to Copy Always
:
<ItemGroup>
<None Update="Workflows\hello-world.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
Configure Blob Storage Workflow Provider
All that’s left is configuring the blob storage workflow provider.
Open the Extensions/ServiceCollectionExtensions.cs
file and add the following lines to the AddElsa
method:
// Get directory path to current assembly.
var currentAssemblyPath = Path.GetDirectoryName(typeof(ServiceCollectionExtensions).Assembly.Location);
// Configure Storage for BlobStorageWorkflowProvider with a directory on disk from where to load workflow definition JSON files from the local "Workflows" folder.
services.Configure<BlobStorageWorkflowProviderOptions>(options => options.BlobStorageFactory = () => StorageFactory.Blobs.DirectoryFiles(Path.Combine(currentAssemblyPath, "Workflows")));
Use your IDE to automatically import missing namespaces or take a look at the completed code snippets.
The result should look like this:
All were doing here is configuring BlobStorageWorkflowProviderOptions
with a blob storage factory method using Storage.NET.
Try it!
To make sure this works, delete the local elsa.sqlite.db
file that you will find in the root of the DocumentManagement.Web
project folder. This ensures that we will not see the workflow as stored in the database, but only the one provided by the JSON file.
Start the DocumentManagement.Web
application and then navigate to the Workflow Definitions screen:
All good. Now navigate to the Workflow Registry screen next:
As you can see, the Hello World workflow was discovered.
Summary
Our application is now configured to provide workflows stored in JSON files. Note that we can still create and manage workflow definitions that are stored in the database. It is now up to you to decide whether you want a given workflow to be part of your project or stored in the database.
Next
In the next part, we will be working on the Document Upload screen of our application and setup Entity Framework Core for persisting Document entities and Storage.NET for storing uploaded files.