
How To Create a Blazor QR Code Scanner
这篇文章探讨了在Blazor应用中使用IronQR(一种.NET库)来集成快速响应码扫描器(QR码扫描器)。 QR码是一个二维条码,能够存储比常规一维条码更多的数据。
Blazor是一个微软框架,允许开发人员制作单页面应用(使用Blazor WebAssembly应用)或使用C#来构建交互式网页界面(Blazor Server,本指南将重点介绍这一点)。
将IronQR与Blazor Server结合用于QR码扫描是一个利用两种技术优势的战略组合。 通过将IronQR与Blazor应用整合,您可以高效地处理QR码的生成和扫描。 在各种商业背景下如库存管理、票务系统和无接触信息共享中,QR码阅读器的这一功能越来越受欢迎。
理解基础知识
什么是Blazor服务器?
Blazor服务器是ASP.NET Core平台的一部分的Web应用框架。 它使开发人员能够使用C#而不是JavaScript来构建交互式网页用户界面。 这种服务器端模型通过处理用户在SignalR连接上的交互来提供实时网络功能。 这帮助开发人员创建有效和交互的网络应用。
IronQR简介
IronQR是一个.NET库,因其能够以高精度读取、解释和生成QR码而脱颖而出。 它提供了一系列功能,包括处理不同类型的QR码内容的能力。 IronQR的优势在于其简单性和易于集成到.NET应用中,使其成为开发人员希望整合和创建QR码功能时的理想选择。
如何创建一个Blazor QR码扫描器
- 在Visual Studio Code中创建Blazor Server应用程序
- 使用NuGet包管理器安装QR码类库
- 使用HTML和CSS在index.razor中创建用户界面
- 编写上传文件处理逻辑
- 使用QR库编写QR扫描逻辑
- 在文本框中显示结果
设置环境
创建一个新的Blazor Server应用程序
启动Visual Studio并选择"创建一个新项目"。在项目模板选择屏幕中,找到并选择"Blazor Server App"模板。

选择模板后,输入项目名称和位置(保留其他内容为默认值),然后单击下一步按钮。

现在选择所需的.NET Framework并点击创建按钮。 它将创建一个Blazor Server应用程序。

安装IronQR库
点击菜单栏中的工具。 从下拉菜单中选择NuGet包管理器。 从上下文菜单中选择"管理解决方案的NuGet包"。 这将打开NuGet包管理器标签。

在NuGet包管理器中,在"浏览"标签下搜索"IronQR"。 然后在列表中找到"IronQR"包。点击"安装"按钮。

现在您已经安装了所有内容,我们可以浏览项目结构,并将一切实现到您的项目中。
实现QR码扫描
构建用户界面
QR码扫描器的用户界面主要构建在Index.razor文件中。这个文件,作为Blazor服务器项目的一部分,使用HTML和Razor语法的结合来创建一个动态和交互的网页。 结构包括:
@page "/"
@using System.IO
@using Microsoft.AspNetCore.Components.Forms
@using IronQr
@using IronSoftware.Drawing
@inject IJSRuntime JSRuntime
<PageTitle>QR Code Scanner</PageTitle>
<div>
<h1>QR Code Scanner</h1>
<InputFile OnChange="HandleSelectedFile" accept="image/*" class="file-input" />
@if (!string.IsNullOrEmpty(qrImageSrcForDisplay))
{
<img src="@qrImageSrcForDisplay" alt="QR Code Image" class="qr-image" />
}
<button @onclick="ScanQRCode" disabled="@(!fileSelected)" class="button scan-button">Scan QR Code</button>
@if (!string.IsNullOrEmpty(scannedText))
{
<div class="result-section">
<input type="text" value="@scannedText" readonly class="result-input" />
<button @onclick="CopyToClipboard" class="button copy-button">Copy</button>
</div>
}
</div>
标题和标题:<h1>标签定义了页面的标题和主要标题,分别设置了用户的上下文。
**图片上传控件:**使用<InputFile>组件上传QR代码图片。 该元素专为仅接受图像文件而设计,通过筛除不相关的文件类型来增强用户体验。
**图像显示:**一旦上传了图像,就会使用<img>标签显示它。 这种视觉反馈对于用户确认上传了正确的文件至关重要。
**扫描按钮:**一个标记为@onclick="ScanQRCode"的按钮触发扫描过程。 其可用性取决于是否选择了文件,增强了界面的直观性。
**结果显示:**扫描的二维码文本将显示在文本输入字段中,方便查看。 另一个按钮允许用户将此文本复制到剪贴板。
在site.css中的CSS样式
QR码扫描器的视觉美感和布局在site.css文件中定义。
.content {
padding: 20px;
margin: 10px auto; /* Centers the content */
max-width: 500px; /* Sets a max width for the content */
border-radius: 10px;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
text-align: center;
}
.file-input, .result-input {
margin: 10px 0;
padding: 10px;
border-radius: 5px;
border: 1px solid #ddd;
width: 100%;
}
.button {
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
padding: 10px;
margin: 10px 0;
border-radius: 5px;
transition: background-color 0.3s, box-shadow 0.3s;
width: auto; /* Adjusts button width */
display: inline-block; /* Allows the width to adjust to content */
}
.button:hover {
background-color: #45a049;
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
.qr-image {
max-width: 300px;
max-height: 300px;
display: block;
margin: 10px auto;
border-radius: 10px;
}
.result-section {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.result-input {
width: 100%;
box-sizing: border-box;
}
.copy-button {
margin-top: 10px;
white-space: nowrap;
}
**.content:**这个类样式化主要内容区域,赋予其一个定义的宽度、中心对齐和用于显示深度的微妙阴影。
**.file-input, .result-input:**这些类样式化文件输入和结果显示元素,确保它们在视觉上保持一致并完全占据其容器的宽度。
**.button:**按钮被样式化为明显的绿色背景、圆角和悬停效果,以提供更好的用户互动。
**.qr-image:**应用于QR码图片的样式包括尺寸限制和自动居中边距,使图像显眼但不至于压倒性。
**.result-section:**此类确保结果部分内的元素居中对齐并适当间隔。
处理文件上传
HandleSelectedFile方法是QR码扫描过程的重要组成部分,负责处理用户的文件上传并准备其进行扫描。 当用户通过<InputFile>组件选择文件时,会触发此方法。 这在以下代码中显示:
private async Task HandleSelectedFile(InputFileChangeEventArgs e)
{
selectedFile = e.File;
fileSelected = true;
var imagesDirectory = Path.Combine(Directory.GetCurrentDirectory(), "UploadedImages");
Directory.CreateDirectory(imagesDirectory); // Ensure the directory exists
// Use a GUID as the unique file name
var uniqueFileName = Guid.NewGuid().ToString() + Path.GetExtension(selectedFile.Name);
var fullPath = Path.Combine(imagesDirectory, uniqueFileName);
await using (var fileStream = new FileStream(fullPath, FileMode.Create))
{
await selectedFile.OpenReadStream().CopyToAsync(fileStream);
}
// Store the full path in qrImageSrc for scanning
qrImageSrc = fullPath;
// Optionally, create a base64 string for displaying the image (if needed)
byte[] imageBytes = await File.ReadAllBytesAsync(fullPath);
var base64String = Convert.ToBase64String(imageBytes);
qrImageSrcForDisplay = $"data:image/{Path.GetExtension(selectedFile.Name).TrimStart('.')};base64,{base64String}";
}Private Async Function HandleSelectedFile(ByVal e As InputFileChangeEventArgs) As Task
selectedFile = e.File
fileSelected = True
Dim imagesDirectory = Path.Combine(Directory.GetCurrentDirectory(), "UploadedImages")
Directory.CreateDirectory(imagesDirectory) ' Ensure the directory exists
' Use a GUID as the unique file name
Dim uniqueFileName = Guid.NewGuid().ToString() & Path.GetExtension(selectedFile.Name)
Dim fullPath = Path.Combine(imagesDirectory, uniqueFileName)
'INSTANT VB TODO TASK: Local functions are not converted by Instant VB:
' await using(var fileStream = New FileStream(fullPath, FileMode.Create))
' {
' await selectedFile.OpenReadStream().CopyToAsync(fileStream);
' }
' Store the full path in qrImageSrc for scanning
qrImageSrc = fullPath
' Optionally, create a base64 string for displaying the image (if needed)
Dim imageBytes() As Byte = Await File.ReadAllBytesAsync(fullPath)
Dim base64String = Convert.ToBase64String(imageBytes)
qrImageSrcForDisplay = $"data:image/{Path.GetExtension(selectedFile.Name).TrimStart("."c)};base64,{base64String}"
End Function以下是其功能的详细分解:
**文件选择与验证:**当用户上传文件时,该方法使用InputFileChangeEventArgs e捕获文件的详细信息。 然后fileSelected设置为true,表示输入数据/文件已准备好处理。
**创建文件路径:**该方法准备一个目录来存储上传的图像。 它使用Directory.CreateDirectory。 此步骤对于系统地组织上传的文件至关重要。
**生成唯一文件名:**为避免与现有文件冲突,使用 GUID(全局唯一标识符)附加到原始文件扩展名来生成唯一文件名。 这确保每个上传的文件都有唯一标识。
**保存文件:**然后将文件保存到服务器。 该方法创建一个指向新生成的文件路径的文件流,并使用await selectedFile.OpenReadStream().CopyToAsync(fileStream)将上传的文件内容复制到该流中。 此步骤完成了上传过程。
**准备显示图像:**文件保存后,需要将图像显示给用户进行确认。 该方法将文件读取为一个字节数组并转换为base64字符串,适合直接嵌入到src属性中。 这种转换允许图像在不需要单独请求服务器提供图像文件的情况下显示。
扫描QR码
ScanQRCode方法是Blazor服务器应用程序中QR码扫描功能的核心。 此方法获取上传的图像并使用IronQR提取QR码数据。
private async Task ScanQRCode()
{
// Check if there is a valid image to work with
if (string.IsNullOrEmpty(qrImageSrc)) return;
try
{
var inputBmp = AnyBitmap.FromFile(qrImageSrc);
QrImageInput imageInput = new QrImageInput(inputBmp);
QrReader reader = new QrReader();
IEnumerable<QrResult> results = reader.Read(imageInput);
// Check if there are any results and if the first result contains text
var firstResult = results.FirstOrDefault();
if (firstResult != null && !string.IsNullOrWhiteSpace(firstResult.Value.ToString()))
{
scannedText = firstResult.Value.ToString();
}
else
{
scannedText = "QR value not found!";
}
}
catch (Exception ex)
{
scannedText = "Error scanning QR code: " + ex.Message;
}
}Private Async Function ScanQRCode() As Task
' Check if there is a valid image to work with
If String.IsNullOrEmpty(qrImageSrc) Then
Return
End If
Try
Dim inputBmp = AnyBitmap.FromFile(qrImageSrc)
Dim imageInput As New QrImageInput(inputBmp)
Dim reader As New QrReader()
Dim results As IEnumerable(Of QrResult) = reader.Read(imageInput)
' Check if there are any results and if the first result contains text
Dim firstResult = results.FirstOrDefault()
If firstResult IsNot Nothing AndAlso Not String.IsNullOrWhiteSpace(firstResult.Value.ToString()) Then
scannedText = firstResult.Value.ToString()
Else
scannedText = "QR value not found!"
End If
Catch ex As Exception
scannedText = "Error scanning QR code: " & ex.Message
End Try
End Function最初,该方法检查持有上传图片路径的qrImageSrc变量是否不为空。 此检查可确保在继续之前有一个有效的图像可以使用。
确认图像已准备好进行处理后,方法会继续QR码读取的核心功能。 这涉及几个关键步骤,首先是将其存储位置的图像加载到适合QR码分析的格式。 这种转换得益于AnyBitmap.FromFile(qrImageSrc)方法,该方法为扫描过程准备图像。
下一步涉及创建一个QrReader对象。 此对象是IronQR库的核心,用作从图像解码QR码的主要工具。 准备好QrReader实例后,应用程序会继续扫描上传的图像。 reader.Read(imageInput)函数负责此操作,系统地搜索图像中的QR代码并提取其数据。
扫描结果存储在IEnumerable<QrResult>集合中。 然后仔细审查此集合以找到第一个QR码结果。 如果检测到一个QR代码,并且其中包含可读文本,则该文本会被捕获并存储在scannedText变量中。 但是,在无法找到QR码或QR码不包含文本的情况下,应用程序设置默认消息以告知用户未检测到QR值。
成功扫描QR码后,文本字符串显示在文本输入字段中,这要归功于Blazor的双向数据绑定功能。 这是通过将scannedText变量绑定到一个文本输入元素来实现的。 输入字段设置为禁用,使其只读。 此设计选择专注于用户的交互,以便查看结果并复制,而不是编辑内容。
整个扫描过程都封装在一个try-catch块中,以防止扫描操作期间出现任何不可预见的错误。 这可能包括与图像文件格式相关的问题或读取过程中的意外错误。 如果发生异常,它将被捕获,并策划并向用户显示一条错误消息。 这种方法有助于在保持与用户透明时跟踪问题,提高应用程序的可靠性。
复制结果
为了启用复制到剪贴板功能,在copyTextToClipboard的JavaScript函数。这个脚本是与剪贴板交互的一种简单而有效的方法:
<script>
function copyTextToClipboard(text) {
navigator.clipboard.writeText(text).then(function () {
console.log('Copying to clipboard was successful!');
}, function (err) {
console.error('Could not copy text: ', err);
});
}
</script>
此功能接受文本参数,即要复制的文本。 它使用一种现代方法navigator.clipboard.writeText与剪贴板进行交互。 由于其简单性和符合网页标准,该方法受到青睐。 它旨在成功复制后在控制台中记录成功消息,帮助调试并确保流畅的功能。 如果出现错误,则将在控制台中记录错误消息,提供在操作过程中遇到的任何问题的见解。
@code部分,作为Blazor应用与JavaScript函数之间的桥梁。 用户界面中的一个按钮单击触发此方法 激活时,它会使用Blazor的JavaScript InterOp功能调用copyTextToClipboard JavaScript函数。 scannedText作为参数传递给此函数,有效地将文本复制到用户的剪贴板。
private async Task CopyToClipboard()
{
await JSRuntime.InvokeVoidAsync("copyTextToClipboard", scannedText);
}Private Async Function CopyToClipboard() As Task
Await JSRuntime.InvokeVoidAsync("copyTextToClipboard", scannedText)
End Function执行应用程序
运行项目后,用户将看到以下干净且简单的界面。 初始屏幕突出显示了QR码扫描器模块。 该模块包括一个上传QR码图像文件的按钮("选择文件")和另一个启动扫描过程的按钮("扫描QR码")。 最初未选择文件,扫描区域为空,等待用户输入。

用户使用"选择文件"按钮选择并上传QR码图像,该按钮现在显示所选文件的名称(例如,"qrvalue.png")。 上传的QR码在界面的指定区域可见,确认图像已准备好进行扫描。

用户单击"扫描QR码"按钮后,应用程序将处理图像。 如果扫描成功,QR码中编码的文本将显示在图像下方。 在这种情况下,扫描结果('<https://ironsoftware.com/csharp/qr/>')是一个URL,指示当用QR阅读器扫描时QR代码将引导用户的地址。 结果旁边出现了一个复制按钮,允许用户轻松地将扫描到的文本复制到剪贴板以供进一步使用。

结论
总而言之,将IronQR整合到Blazor Server应用程序中的过程顺畅而有效,最终形成了一种QR码扫描解决方案。 由于IronQR强大的处理与Blazor的动态UI渲染相结合,从项目设置到扫描功能的实现都体现了其实用性从而易于使用。 从环境设置到部署的过程强调了这种集成在现实应用中的实用性和有效性。 虽然IronQR擅长QR码,但对于需要扫描条码功能的项目,IronBarcode是个理想的选择,提供了类似的使用和集成水平。
IronQR提供免费试用版,供开发人员在购买之前探索其功能。 为了在生产中扩展使用并访问其所有专业功能,IronQR许可证从$999起。

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。
相关文章


