How to Build Web Barcode and QR Code Reader with Blazor WebAssembly

Xiao Ling - Apr 25 '22 - - Dev Community

Blazor is a web framework developed by Microsoft. It enables developers to create web apps using C# and HTML. However, calling existing JavaScript API is inevitable while developing a Blazor project. This article will help web developers who want to build web barcode and QR code reader apps using Blazor WebAssembly and Dynamsoft JavaScript Barcode SDK.

How to Use Dynamsoft JavaScript Barcode SDK

Include <script src="https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode@9.0.0/dist/dbr.js"></script> in your HTML file.

Apply for a 30-day trial license to activate the SDK:

Dynamsoft.DBR.BarcodeReader.license = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==";
Enter fullscreen mode Exit fullscreen mode

Blazor Architecture Overview

Blazor provides two templates: Blazor WebAssembly and Blazor Server.

Blazor WebAssembly

Blazor WebAssembly

Blazor Server

Blazor-server

Blazor server runs client-side UI logic on the server-side and sends the UI changes via Websocket. To conveniently handle JavaScript interop calls, we pick Blazor WebAssembly to implement the web barcode and QR code reader.

New to Blazor WebAssembly Project

Create a Blazor App with the Blazor WebAssembly template:

dotnet new blazorwasm -o BlazorBarcodeSample
Enter fullscreen mode Exit fullscreen mode

Then add a new page to the project:

cd BlazorBarcodeSample
dotnet new razorcomponent -n BarcodeReader -o Pages
Enter fullscreen mode Exit fullscreen mode

After that, add a BarcodeReader attribute to Pages/Index.razor:

@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />
<BarcodeReader />
Enter fullscreen mode Exit fullscreen mode

So far, we can run the app and view the homepage:

dotnet run
Enter fullscreen mode Exit fullscreen mode

Blazor hello world

When running the app for the first time, we can open the developer console to observe what is going on.

blazor wasm

A dotnet.wasm file and some *.dll files are fetched and cached by the web browser.

After making some changes and rebuild the project, we will find that only the BlazorBarcodeSample.dll has been fetched again.

blazor component

Reading Barcode and QR Code in Blazor WebAssembly

We add Dynamsoft JavaScript Barcode SDK to wwwroot/index.html, and then create a jsInterop.js file for interoperation between JavaScript and .NET:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>BlazorBarcodeSample</title>
    <base href="/" />
    <link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="BlazorBarcodeSample.styles.css" rel="stylesheet" />
    <script src="https://cdn.jsdelivr.net/npm/dynamsoft-javascript-barcode@9.0.0/dist/dbr.js"></script>
</head>

<body>
    <script src="_framework/blazor.webassembly.js"></script>
    <script src="jsInterop.js"></script>
</body>

</html>
Enter fullscreen mode Exit fullscreen mode

In jsInterop.js, we initialize Dynamsoft Barcode Reader and use a JavaScript variable to save the reference of the .NET object:

let barcodescanner = null;
let dotnetRef = null;
window.jsFunctions = {
    init: function(obj) {
        let result = true;
        try {
            Dynamsoft.DBR.BarcodeReader.license = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==";
            barcodescanner = await Dynamsoft.DBR.BarcodeScanner.createInstance();
            await barcodescanner.updateRuntimeSettings("balance");
            dotnetRef = obj;
        } catch (e) {
            console.log(e);
            result = false;
        }
        return result;
    },
};
Enter fullscreen mode Exit fullscreen mode

The JavaScript init() function will be triggered by the OnInitialized() method in BarcodeReader.razor:

@inject IJSRuntime JSRuntime

@if (initialized == false)
{
    <p>Initializing...</p>
}
else
{
}

@code {
    Boolean initialized = false;

    protected override void OnInitialized()
    {
        Init();
    }

    public async void Init()
    {
        initialized = await JSRuntime.InvokeAsync<Boolean>("jsFunctions.init", DotNetObjectReference.Create(this));
        StateHasChanged();
    }

}
Enter fullscreen mode Exit fullscreen mode

To select an image file from the disk drive, we use the InputFile component:

<InputFile OnChange="LoadImage" />
@code {
    private async Task LoadImage(InputFileChangeEventArgs e)
    {
        var imageFile = e.File;
        var jsImageStream = imageFile.OpenReadStream(1024 * 1024 * 20);
        var dotnetImageStream = new DotNetStreamReference(jsImageStream);
        await JSRuntime.InvokeVoidAsync("jsFunctions.setImageUsingStreaming", 
            "image", dotnetImageStream);
    }
}
Enter fullscreen mode Exit fullscreen mode

As the image is loaded, we call the setImageUsingStreaming() method in jsInterop.js to pass the image data:

function returnResultsAsString(results) {
    let txts = [];
    try {
        for (let i = 0; i < results.length; ++i) {
            txts.push(results[i].barcodeText);
        }
        let barcoderesults = txts.join(', ');
        if (txts.length == 0) {
            barcoderesults = 'No barcode found';
        }
        if (dotnetRef) {
            dotnetRef.invokeMethodAsync('ReturnBarcodeResultsAsync', barcoderesults);
        }
    } catch (e) {
    }
}

setImageUsingStreaming: async function setImageUsingStreaming(imageElementId, imageStream) {
        const arrayBuffer = await imageStream.arrayBuffer();
        const blob = new Blob([arrayBuffer]);
        const url = URL.createObjectURL(blob);
        document.getElementById(imageElementId).src = url;
        document.getElementById(imageElementId).style.display = 'block';

        if (barcodescanner) {
            try {
                let results = await barcodescanner.decode(blob);
                returnResultsAsString(results);
            } catch (ex) {
                alert(ex.message);
                throw ex;
            }
        }

      },
Enter fullscreen mode Exit fullscreen mode

In the meantime, we invoke the decode() method to read barcode and QR code from the image buffer and then pass the results to the ReturnBarcodeResultsAsync() method in BarcodeReader.razor:

[JSInvokable]
public void ReturnBarcodeResultsAsync(String text)
{
    result = text;
    StateHasChanged();
}
Enter fullscreen mode Exit fullscreen mode

Now we can test the Blazor WebAssembly app with some barcode and QR code images.

code93

blazor barcode sample

Live Scan Barcode and QR Code Using Camera

In addition to decoding barcode and QR code from static files, we can also do real-time scan with a connected camera.

In the BarcodeReader.razor file, we add a live scan button:

<button class="btn btn-primary" @onclick="LiveScan">Live Scan</button>

@code {
    public async Task LiveScan()
    {
        await JSRuntime.InvokeVoidAsync(
                "jsFunctions.liveScan");
    }
}
Enter fullscreen mode Exit fullscreen mode

Then add the corresponding JavaScript function in the jsInterop.js:

liveScan: async function () {
    if (barcodescanner) {
        barcodescanner.onFrameRead = async results => {
            if (results.length > 0) {
                console.log("onFrameRead");
                returnResultsAsString(results);
            }
        };
        await barcodescanner.show();
    } else {
        alert("The barcode reader is still initializing.");
    }
},
Enter fullscreen mode Exit fullscreen mode

When we click the button, a popup window that contains a camera preview and camera source list will appear.

Here is the final look of the project:

Blazor WebAssembly barcode

Source Code

https://github.com/yushulx/blazor-barcode-qrcode-reader-scanner

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player