在生产环境中测试,无水印。
随时随地满足您的需求。
获得30天的全功能产品。
几分钟内就能启动并运行。
在您的产品试用期间,全面访问我们的支持工程团队。
本文探讨了在使用IronQR(一个.NET库)的Blazor应用程序中集成快速响应码扫描器(QR码扫描器)。 QR 码是一种二维条形码,与普通的一维条形码相比,它能存储更多的数据。
Blazor是一个微软框架,允许开发者创建单页面应用程序(使用Blazor WebAssembly应用)或者使用C#构建交互式Web界面(Blazor Server,这也是我们将在本指南中关注的重点)。
IronQR 与 Blazor Server 在二维码扫描方面的集成是一种战略性组合,充分利用了两种技术的优势。 通过将 IronQR 与 Blazor 应用程序集成,您可以高效地处理二维码的生成和扫描。 二维码阅读器的这一功能在库存管理、票务系统和非接触式信息共享等各种商业环境中的需求日益增长。
Blazor Server 是 ASP.NET Core 平台的一部分的 Web 应用框架。 它使开发人员能够使用 C# 而不是 JavaScript 构建交互式 Web UI。 这种服务器端模型通过 SignalR 连接(一种实时网络功能)处理用户交互。 这有助于开发人员创建有效的交互式网络应用程序。
IronQR 是一个 .NET 库,以其读取、解释和生成二维码的高准确性而著称。 它提供了一系列功能,包括处理不同类型二维码内容的能力。 IronQR 的优势在于简单易用,易于集成到 .NET 应用程序中,是希望集成和创建 QR 代码功能的开发人员的首选。
在 Visual Studio 代码中创建 Blazor 服务器应用程序
使用 NuGet 软件包管理器安装 QR 代码类库
在 index.razor 中使用 HTML 和 CSS 创建用户界面
编写上传文件处理逻辑
使用 QR 库编写 QR 扫描逻辑
启动 Visual Studio 并选择 "创建新项目"。在项目模板选择界面,找到并选择 "Blazor Server App "模板。 单击下一步。
选择模板后,输入项目名称和位置(保留其他所有内容为默认值),然后点击“下一步”按钮。
现在选择所需的 .NET Framework 并点击创建按钮。 它将创建一个 Blazor 服务器应用程序。
单击菜单栏中的 "工具"。 从下拉菜单中选择 NuGet 包管理器。 从上下文菜单中选择 "管理解决方案的 NuGet 包"。 这将打开 NuGet 包管理器选项卡。
在 NuGet 包管理器中,在 "浏览 "选项卡中搜索 "IronQR"。 然后在列表中找到 "IronQR "软件包。点击 "安装 "按钮。
现在,您已经安装好了所有工具,我们可以了解一下项目结构以及如何在您的项目中实施所有工具。
QR Code Scanner 的用户界面主要构建在 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(qrImageSrc))
{
<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">
<button @onclick="CopyToClipboard" class="button copy-button">Copy</button>
</div>
}
</div>
@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(qrImageSrc))
{
<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">
<button @onclick="CopyToClipboard" class="button copy-button">Copy</button>
</div>
}
</div>
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: @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(qrImageSrc))
"image/*" Class="file-input" /> [if](Not String.IsNullOrEmpty(qrImageSrc))
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: Friend @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
"HandleSelectedFile" accept="image/*" Class
Friend page "/" [using] System.IO [using] Microsoft.AspNetCore.Components.Forms [using] IronQr [using] IronSoftware.Drawing inject IJSRuntime JSRuntime (Of PageTitle) QR Code Scanner</PageTitle> (Of div) (Of h1) QR Code Scanner</h1> <InputFile OnChange="HandleSelectedFile" accept
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <img src="@qrImageSrcForDisplay" alt="QR Code Image" class="qr-image" />
"QR Code Image" class="qr-image" />
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <img src="@qrImageSrcForDisplay" alt="QR Code Image" class
"@qrImageSrcForDisplay" alt="QR Code Image" class
<img src="@qrImageSrcForDisplay" alt
End Class
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <button onclick="ScanQRCode" disabled="@(!fileSelected)" class="button scan-button"> Scan QR Code</button> if(!string.IsNullOrEmpty(scannedText))
"@(!fileSelected)" class="button scan-button"> Scan QR Code</button> [if](Not String.IsNullOrEmpty(scannedText))
If True Then
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <button onclick="ScanQRCode" disabled="@(!fileSelected)" class
"ScanQRCode" disabled="@(!fileSelected)" class
<button onclick="ScanQRCode" disabled
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <div class="result-section"> <button onclick="CopyToClipboard" class="button copy-button"> Copy</button> </div>
"CopyToClipboard" class="button copy-button"> Copy</button> </div>
'INSTANT VB WARNING: An assignment within expression was extracted from the following statement:
'ORIGINAL LINE: <div class="result-section"> <button onclick="CopyToClipboard" class
"result-section"> <button onclick="CopyToClipboard" class
<div class="result-section"> <button onclick
End If
'INSTANT VB TODO TASK: The following line uses invalid syntax:
'</div>
标题和标题:<PageTitle>
和 <h1>
标签分别定义页面的标题和主要标题,为用户设置上下文。
图片上传控件:使用<InputFile>
组件上传二维码图片。 该元素只接受图像文件,通过过滤掉不相关的文件类型来增强用户体验。
图像显示:一旦上传图像,将使用<img>
标签显示。 这种视觉反馈对于确保用户上传了正确的文件至关重要。
扫描按钮:一个标记为@onclick="ScanQRCode
的按钮会触发扫描过程。 其可用性取决于文件是否被选中,从而增强界面的直观性。
结果显示:扫描的 QR 码文本显示在一个文本输入框中,便于查看。 用户可以通过一个单独的按钮将这些文本复制到剪贴板。
QR Code Scanner 的视觉美学和布局在 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
:应用于二维码图像的样式包括尺寸限制和用于居中的自动边距,使图像突出而不显得过于醒目。
.result-section
:这个类确保结果部分内的元素居中对齐并间距适当。
HandleSelectedFile
方法是二维码扫描过程中的关键部分,负责处理用户的文件上传并准备进行扫描。 当用户通过<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 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捕获文件的详细信息。 selectedFile
变量然后被分配给这个文件,并且布尔值 fileSelected
被设置为 true,指示输入数据/文件已准备好进行处理。
创建文件路径:该方法准备一个目录以存储上传的图像。 它使用Path.Combine
来创建指向'UploadedImages
'目录的路径,并使用Directory.CreateDirectory
确保该目录存在。 这一步对于系统整理上传的文件至关重要。
生成唯一文件名:为了避免与现有文件发生冲突,使用 GUID(全局唯一标识符)生成一个唯一文件名,并附加原文件的扩展名。 这确保每个上传的文件都被uniquePathdentified
。
保存文件: 然后将文件保存到服务器。 该方法创建一个指向新生成文件路径的文件流,并使用await selectedFile.OpenReadStream().CopyToAsync(fileStream)
将上传文件的内容复制到此流中。 这一步完成了上传过程。
准备图像以供显示:文件保存后,有必要将图像再次显示给用户以进行确认。 该方法将文件读取到字节数组中,并将其转换为 base64 字符串,适合直接嵌入到 <img>
标签的 src
属性中。 这种转换可以显示图像,而不需要向服务器单独请求图像文件。
ScanQRCode
方法是 Blazor Server 应用程序中二维码扫描功能的核心。 该方法获取上传的图片,并使用 IronQR 提取二维码数据。
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 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 代码分析的格式。 这种转换由 AnyBitmap.FromFile(qrImageSrc)
方法实现,它将图像准备好进行扫描过程。
下一步涉及创建一个QrReader
对象。 该对象是 IronQR 库不可或缺的一部分,是从图像中解码二维码的主要工具。 当 QrReader
实例准备就绪时,应用程序随后继续扫描上传的图像。 reader.Read(imageInput)
函数负责此操作,系统地搜索图像中的二维码并提取其数据。
扫描结果存储在IEnumerable<QrResult>
集合中。 然后,我们会仔细检查这组译文,以找到第一个二维码结果。 如果检测到二维码,并且其中包含可读文本,则该文本会被捕获并存储在scannedText
变量中。 不过,在未找到二维码或二维码不包含文本的情况下,应用程序会设置一条默认消息,告知用户未检测到二维码值。
一旦成功扫描二维码,文本字符串就会显示在文本输入框中,这要归功于 Blazor 的双向数据绑定功能。 这通过将scannedText
变量绑定到一个文本输入元素来实现。 输入字段设置为禁用,只读。 这种设计选择将用户交互的重点放在查看结果和复制结果上,而不是编辑内容。
整个扫描过程都包含在一个 try-catch 块中,以防止在扫描操作过程中出现意外错误。 这可能包括与图像文件格式相关的问题或阅读过程中的意外错误。 如果出现异常,就会捕捉到异常,并编写错误信息显示给用户。 这种方法不仅有助于发现问题,还能保持对用户的透明度,提高应用程序的可靠性。
要启用复制到剪贴板功能,需要在_Host.cshtml
文件中定义一个名为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
方法,这是一种与剪贴板交互的现代方法。 这种方法因其简单性和符合网络标准而受到青睐。 设计的目的是在复制成功后在控制台中记录一条成功信息,以帮助调试并确保功能顺畅。 如果出现错误,错误信息将记录到控制台,以便深入了解操作过程中遇到的任何问题。
CopyToClipboard
方法位于 index.razor 文件的 @code
部分,作为 Blazor 应用程序与 JavaScript 函数之间的桥梁。 用户界面中的按钮可触发该方法的点击。 激活时,它会使用Blazor的JavaScript InterOp功能调用copyTextToClipboard
JavaScript函数。 scannedText
被作为参数传递给该函数,从而有效地将文本复制到用户的剪贴板。
private async Task CopyToClipboard()
{
await JSRuntime.InvokeVoidAsync("copyTextToClipboard", 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码图像,现在显示所选文件的名称(例如,“qrvalue.png”)。 上传的 QR 代码在界面上的指定区域可见,向用户确认图像已准备好扫描。
用户点击 "扫描二维码 "按钮后,应用程序将处理图像。 如果扫描成功,二维码内的编码文本就会显示在图片下方。 在这种情况下,扫描结果 ('<https://ironsoftware.com/csharp/qr/>'
) 是一个URL,指示扫描二维码时用户会被引导到的位置。 结果旁边会出现 "复制 "按钮,用户可以轻松地将扫描文本复制到剪贴板,以便进一步使用。
总之,将 IronQR 集成到 Blazor 服务器应用程序中的过程是顺利而有效的,从而形成了一个二维码扫描解决方案。 由于混合使用了 IronQR 的强大处理功能和 Blazor 的动态用户界面渲染功能,从开始设置这个项目到实现扫描功能,都具有响应性和易用性。 从设置环境到部署的整个过程都要强调这种集成在实际应用中的实用性和有效性。 虽然IronQR擅长处理QR码,但对于需要扫描条形码功能的项目,IronBarcode是一个理想的选择,提供了类似的易用性和集成水平。
IronQR 为开发人员提供免费试用,以便在购买之前探索其功能。 若要在生产中扩展使用并访问其所有专业功能,IronQR 许可证的起始价格为$749。