Part 3 of Building Workflow Driven .NET Applications with Elsa 2

Executing workflows from JSON files & Workflow Providers

Sipke Schoorstra
6 min readAug 1, 2021

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 BlobStorageWorkflowProviderto 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:

src/DocumentManagement.Workflows/Extensions/ServiceCollectionExtensions.cs

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.Webapplication and then navigate to the Workflow Definitions screen:

Nothing to see here, as expected

All good. Now navigate to the Workflow Registry screen next:

Hello World workflow provided by hello-world.json

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.

--

--