在生產環境中測試,無水印。
在任何需要的地方都能運行。
獲得 30 天的全功能產品。
在幾分鐘內上手運行。
試用產品期間完全訪問我們的支援工程團隊
本文探討如何在 Blazor 應用程式中使用 IronQR 結合快取回應碼掃描器(QR code scanner),這是一個 .NET 程式庫。 QR 碼是二維條碼,能夠儲存比一般一維條碼更多的數據。
Blazor 是一個 Microsoft 框架,允許開發人員使用 Blazor WebAssembly 應用程式來製作單頁應用程式,或使用 C# 建構互動式網頁介面(Blazor Server,也是我們在本指南中將專注的重點)。
將IronQR與Blazor Server整合以進行QR碼掃描是一種戰略性的組合,能夠發揮兩項技術的優勢。 通過將 IronQR 與 Blazor 應用程式整合,您可以高效處理 QR 碼的生成和掃描。 在庫存管理、票務系統和無接觸信息共享等各種商業環境中,QR 碼閱讀器的此功能需求日益增長。
Blazor Server 是 ASP.NET Core 平台的一部分的 web 應用程式框架。 它使開發人員能夠使用C#而不是JavaScript來構建互動式網頁用戶介面。 此伺服器端模型通過處理用戶在 SignalR 連接上的互動來運行,這是一種即時網頁功能。 這有助於開發人員創建有效且互動的網絡應用程式。
IronQR 是一個 .NET 函式庫,以其具有高度準確性讀取、解析和生成 QR 碼的能力而著稱。 它提供了一系列功能,包括處理不同類型的QR碼內容的能力。 IronQR的優勢在於其簡單性及易於整合到.NET應用程式中,使其成為開發人員在尋求融入和創建QR碼功能時的首選。
在 Visual Studio Code 中創建 Blazor 伺服器應用程式
使用 NuGet 套件管理器安裝 QR Code 類別庫
在 index.razor 中使用 HTML 和 CSS 創建用戶介面。
編寫上傳文件處理邏輯
使用QR庫編寫QR掃描邏輯。
啟動 Visual Studio,然後選擇「建立新專案」。在專案範本選擇畫面中,找到並選擇「Blazor Server App」範本。 點擊下一步。
選擇範本後,輸入專案名稱和位置(其他保持為預設值)並點擊下一步按鈕。
現在選擇所需的 .NET Framework 並點擊創建按鈕。 它將創建一個Blazor Server應用程式。
從選單列中點擊工具。 從下拉選單中選擇 NuGet 套件管理員。 從內容選單中,選擇「管理解決方案的 NuGet 套件」。 這將開啟 NuGet 套件管理器標籤。
在 NuGet 套件管理器中,在「瀏覽」選項卡中搜尋「IronQR」。 然後在列表中找到「IronQR」套件。點擊「安裝」按鈕。
現在您已安裝好所有內容,我們可以探討項目結構以及如何將所有東西整合到您的項目中。
QR 码扫描器的使用者介面主要构建在Index.razor文件中。这个文件是 Blazor Server 项目的一部分,使用 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>
元件來上傳 QR 碼圖片。 此元件專門設計用於僅接受圖像文件,通過過濾不相關的文件類型來提升使用者體驗。
影像顯示:一旦上傳影像,將使用<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
:應用於 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 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 伺服器應用程式中 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 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 code 結果。 如果偵測到 QR 碼,且該碼包含可讀取的文字,這些文字將被捕獲並儲存在scannedText
變數中。 然而,在找不到 QR 碼或不包含文本的情況下,應用程式會設定一條預設訊息來告知使用者未檢測到 QR 值。
成功掃描 QR 碼後,文字字串會顯示在文字輸入欄位中,這要歸功於 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 Code掃描器模組。 此模組包括一個用於上傳 QR 碼圖像檔案的按鈕(‘選擇檔案’),以及另一個用於啟動掃描過程的按鈕(‘掃描 QR 碼’)。 最初,未選擇任何檔案,掃描區域是空白的,等待使用者輸入。
使用者使用「選擇檔案」按鈕選取並上傳 QR 碼圖像,現在會顯示選取的檔案名稱(例如,「qrvalue.png」)。 上傳的 QR 碼顯示在介面上的指定區域,確認圖像已準備好進行掃描。
當使用者點擊「掃描 QR Code」按鈕後,應用程式會處理該圖片。 如果掃描成功,QR碼中的文本會顯示在圖像下方。 在這種情況下,掃描結果('<https://ironsoftware.com/csharp/qr/>'
)是一個 URL,表示當用 QR 讀取器掃描 QR 碼時會將用戶引導到的位置。 結果旁邊會顯示複製按鈕,允許使用者輕鬆地將掃描的文字複製到剪貼簿以便進一步使用。
總結來說,將 IronQR 整合到 Blazor Server 應用程式的過程既順暢又有效,從而提供了一個 QR 碼掃描解決方案。 自專案設立之初到實現掃描功能為止,得益於 IronQR 強大的處理能力與 Blazor 動態 UI 呈現的結合,操作上回應快速且易於使用。 從設置環境到部署的過程,強調了此整合在實際應用中的實用性和有效性。 雖然 IronQR 專精於 QR 碼,但對於需要掃描條碼功能的專案,IronBarcode 是理想的選擇,提供類似的易用性和整合性。
IronQR 為開發人員提供免費試用,以探索其功能在購買之前。 為了在生產中擴展使用並訪問其所有專業功能,IronQR 授權的起價為 $749。