DEV Community

Cover image for Unlock the Power of Microsoft Blazor: Seamless Integration with Workflow Designer — Check Out Guide Now!
Optimajet Limited
Optimajet Limited

Posted on • Updated on • Originally published at workflowengine.io

Unlock the Power of Microsoft Blazor: Seamless Integration with Workflow Designer — Check Out Guide Now!

Intro

Before we dive into the main guide on integrating Workflow Designer with Blazor, it makes sense to convey to readers the practical benefits of using workflow engines in applications. If you haven't considered this before, or if you have but lacked the motivation to implement a Workflow Engine, then this YouTube video by Jeff Fritz will surely captivate you. Jeff Fritz a principal program manager in Microsoft’s Developer Division working on the .NET Community Team. We are confident that this video will help you understand the benefits of implementing a Workflow Engine with a visual Workflow editor and dispel any doubts you may have.

Jeff Fritz explains in a simple and accessible manner, using a delivery case example, how using a workflow engine helps simplify development and reduces the time and effort spent on refactoring and testing

Overview

Not all .NET backend developers have expertise in popular frontend frameworks like React or Angular. However, .NET backend developers often possess skills in Microsoft Blazor. We have frequently received requests from our technical support team to create an example of integrating the community version of Optimajet WorkflowEngine (which includes a visual designer) with Microsoft Blazor. We have accomplished this and are sharing an example and guide with you on GitHub repository).

Let's start by creating an application using the blazorserver template.

mkdir workflow-designer-blazor
cd workflow-designer-blazor
dotnet new blazorserver
Enter fullscreen mode Exit fullscreen mode

We can run this application using the dotnet watch command and modify its code on the fly. This is a great feature of the dotnet CLI! If
you run the application and open it in a browser, you will see something like this:

Empty Blazor application

Empty Blazor application

What we are going to add:

  1. CSS and JS files for Workflow Designer from CDN.
  2. Designer navigation element on the left panel with the corresponding page.
  3. Workflow Designer on a new Blazor page.

Adding CSS and JS Workflow for Workflow Designer

First, we need to add CSS and JS from Workflow Designer to our application so that we can connect the Designer to a new page. We will also
need to connect jQuery, since Workflow Designer uses it in its work.

We will use CDN, just to avoid copying Designer files to the project. Of course, you can use local files instead of CDN, this is especially
important when you work in an environment with limited Internet access.

info important

Due to the way Blazor works with JavaScript code, external JavaScript code must be included after the script blazor.server.js.

Open the Pages/_Host.cshtml file and add the highlighted lines as shown below. Styles are added inside the <head> tag, scripts are added to the end of the page.

Pages/_Host.cshtml

@page "/"
@using Microsoft.AspNetCore.Components.Web
@namespace workflow_designer_blazor.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <base href="~/"/>
    <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css"/>
    <link href="css/site.css" rel="stylesheet"/>
    <link href="workflow-designer-blazor.styles.css" rel="stylesheet"/>
    <link rel="stylesheet" href="https://unpkg.com/@@optimajet/workflow-designer@12.5.1/dist/workflowdesigner.min.css">
    <link rel="icon" type="image/png" href="favicon.png"/>
    <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered"/>
</head>
<body>
<component type="typeof(App)" render-mode="ServerPrerendered"/>

<div id="blazor-error-ui">
    <environment include="Staging,Production">
        An error has occurred. This application may no longer respond until reloaded.
    </environment>
    <environment include="Development">
        An unhandled exception has occurred. See browser dev tools for details.
    </environment>
    <a href="" class="reload">Reload</a>
    <a class="dismiss">🗙</a>
</div>

<script src="_framework/blazor.server.js"></script>
// &new>
<script
        src="https://code.jquery.com/jquery-3.7.1.min.js"
        integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo="
        crossorigin="anonymous"></script>
<script src="https://unpkg.com/@@optimajet/workflow-designer@12.5.1/dist/workflowdesignerfull.min.js"
        async defer>
</script>
<script src="js/designerInterop.js"></script>
// <&new
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Now the Workflow Designer with its styles will be loaded in our application.

Pay attention to the file js/designerInterop.js. This is a file that will contain auxiliary functions for working with the Designer.
Let's create it in the wwwroot/js/designerInterop.js path:

wwwroot/js/designerInterop.js

function renderWorkflowDesigner(options) {
    var wfdesigner = new WorkflowDesigner({
        apiurl: options.apiUrl,
        name: 'wfe',
        language: 'en',
        renderTo: options.elementId,
        graphwidth: window.innerWidth - 400,
        graphheight: window.innerHeight - 100,
        showSaveButton: true,
    })

    const data = {
        schemecode: options.schemeCode,
        processid: options.processId
    }

    if (wfdesigner.exists(data)) {
        wfdesigner.load(data)
    } else {
        wfdesigner.create(data.schemecode)
    }
}

function waitForJsAndRender(options) {
    if (typeof window.WorkflowDesigner !== 'undefined') {
        renderWorkflowDesigner(options)
        return
    }

    // the interval here is only needed to wait for the javascript to load with the designer
    const interval = setInterval(() => {
        // if the designer hasn't been uploaded yet, we'll wait a little longer
        if (typeof window.WorkflowDesigner === 'undefined') return

        clearInterval(interval)
        renderWorkflowDesigner(options)
    }, 30)
}
Enter fullscreen mode Exit fullscreen mode

There are only two functions in the file:

  1. renderWorkflowDesigner - renders the Designer with the specified options.
  2. waitForJsAndRender - waits for JavaScript to load with the Designer and calls the Designer's render. We need this function because the Designer loads asynchronously after the page loads.

Adding a new page

Open the Shared/NavMenu.razor file and add the highlighted lines after the Fetch data navigation link.

Shared/NavMenu.razor


<div class="@NavMenuCssClass nav-scrollable" @onclick="ToggleNavMenu">
    <nav class="flex-column">
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="counter">
                <span class="oi oi-plus" aria-hidden="true"></span> Counter
            </NavLink>
        </div>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="fetchdata">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
            </NavLink>
        </div>
        // &new>
        <div class="nav-item px-3">
            <NavLink class="nav-link" href="designer">
                <span class="oi oi-copywriting" aria-hidden="true"></span> Designer
            </NavLink>
        </div>
        // <&new
    </nav>
</div>
Enter fullscreen mode Exit fullscreen mode

Now add a new file Pages/Designer.razor and paste the following content there:

Pages/Designer.razor

@page "/designer"
@inject IJSRuntime JSRuntime

<PageTitle>Workflow designer</PageTitle>

<div id="root"></div>

@code
{
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            var options = new
            {
                apiUrl = "https://demo.workflowengine.io/Designer/API",
                elementId = "root",
                schemeCode = "SimpleWF"
            };
            await JSRuntime.InvokeAsync<Task>("waitForJsAndRender", options);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Everything is quite simple here. There is a div element on the page with the id root. When the page is first rendered, in the
OnAfterRenderAsync method, we call a JavaScript function called waitForJsAndRender, passing in options as parameters.

In the parameters we pass:

  1. elementId - the identifier of the HTML element in which Designer should be drawn.
  2. apiUrl - the URL where Designer's API is located.
  3. schemeCode - the scheme code.

Launching the application

Now you can run your application using the dotnet run or dotnet watch command. After that, open your browser and navigate to a new page where you should see Workflow Designer.

Workflow Designer in Blazor application

Workflow Designer in Blazor application

Conclusion

We have added Workflow Designer to our Blazor application by including a script from a content delivery network (CDN).
To work with the designer, we used the JavaScript interop mechanism.
It was quite easy!

Your feedback is very important to us
It helps us understand whether this guide was useful to you, how clearly it was written, and what else you would like to learn about. Please ask your questions in the comments or start discussions on GitHub.

Top comments (0)