How to Build Web Barcode and QR Code Reader with Blazor WebAssembly
Tags: blazor, cshap, dotnet, webdev
Published: 2022-04-25 02:23:06

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](https://www.dynamsoft.com/barcode-reader/sdk-javascript/).

## 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](https://www.dynamsoft.com/customer/license/trialLicense?product=dbr) to activate the SDK:

```js
Dynamsoft.DBR.BarcodeReader.license = "DLS2eyJoYW5kc2hha2VDb2RlIjoiMjAwMDAxLTE2NDk4Mjk3OTI2MzUiLCJvcmdhbml6YXRpb25JRCI6IjIwMDAwMSIsInNlc3Npb25QYXNzd29yZCI6IndTcGR6Vm05WDJrcEQ5YUoifQ==";
```


## Blazor Architecture Overview

Blazor provides two templates: Blazor WebAssembly and Blazor Server.

**Blazor WebAssembly**

![Blazor WebAssembly](https://docs.microsoft.com/en-us/aspnet/core/blazor/index/_static/blazor-webassembly.png?view=aspnetcore-3.1)

**Blazor Server**

![Blazor-server](https://docs.microsoft.com/en-us/aspnet/core/blazor/index/_static/blazor-server.png?view=aspnetcore-3.1)

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:

```powershell
dotnet new blazorwasm -o BlazorBarcodeSample
```

Then add a new page to the project:

```powershell
cd BlazorBarcodeSample
dotnet new razorcomponent -n BarcodeReader -o Pages
```

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

```cs
@page "/"

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />
<BarcodeReader />
```

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

```powershell
dotnet run
```

![Blazor hello world](https://www.dynamsoft.com/codepool/img/2020/09/blazor-init-ui-1000x402.png)

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

![blazor wasm](https://www.dynamsoft.com/codepool/img/2020/09/blazor-wasm-1000x543.png)

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](https://www.dynamsoft.com/codepool/img/2020/09/blazor-component.png)

## Reading Barcode and QR Code in Blazor WebAssembly

We add [Dynamsoft JavaScript Barcode SDK](https://www.dynamsoft.com/Products/barcode-recognition-javascript.aspx) to `wwwroot/index.html`, and then create a `jsInterop.js` file for interoperation between JavaScript and .NET:

```html
<!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>
```

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

```js
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;
    },
};
```

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

```js
@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();
    }
    
}
```

To select an image file from the disk drive, we use the [InputFile component](https://docs.microsoft.com/en-us/aspnet/core/blazor/images?view=aspnetcore-6.0#streaming-examples):

```js
<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);
    }
}
```

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

```js
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;
            }
        }
        
      },
```

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

```cs
[JSInvokable]
public void ReturnBarcodeResultsAsync(String text)
{
    result = text;
    StateHasChanged();
}
```

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

![code93](https://www.dynamsoft.com/codepool/img/2020/09/code93-1000x506.png)

![blazor barcode sample](https://www.dynamsoft.com/codepool/img/2020/09/blazor-barcode-sample.png)

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

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

@code {
    public async Task LiveScan()
    {
        await JSRuntime.InvokeVoidAsync(
                "jsFunctions.liveScan");
    }
}
```

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

```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.");
    }
},
```

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](https://www.dynamsoft.com/codepool/img/2022/04/blazor-barcode-qrcode-reader.png)

## Source Code

[https://github.com/yushulx/blazor-barcode-qrcode-reader-scanner](https://github.com/yushulx/blazor-barcode-qrcode-reader-scanner)