From d01fb45ec123353bf8901cdfc7de26932e48c086 Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Sat, 10 Oct 2026 23:31:36 +0200 Subject: [PATCH 1/2] QRCoder: .NET 10, QRCoder 1.8.0, SVG renderer, thread-safe QrCodesDb Retarget both projects to net10.0 and bump QRCoder to 1.8.0 and the test packages. GeneratePng renders black on white again; the coloured call moves to GeneratePngBranded. Add GenerateQRCodeSvg with SvgQRCode. QrCodesDb uses ConcurrentDictionary with TryAdd. Drop the stray semicolon on @model, switch to MapStaticAssets, and add PNG and SVG output tests. --- .../Controllers/HomeController.cs | 30 ++++++++++- .../QRCodeGeneratorWebSample/Program.cs | 6 ++- .../QRCodeGeneratorWebSample.csproj | 4 +- .../QRCodeGeneratorWebSample/QrCodesDb.cs | 10 ++-- .../Views/Home/Index.cshtml | 4 +- .../Tests/QRCodeGeneratorWebSampleUnitTest.cs | 52 ++++++++++++++++--- .../QRCoder/Tests/Tests.csproj | 10 ++-- 7 files changed, 90 insertions(+), 26 deletions(-) diff --git a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Controllers/HomeController.cs b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Controllers/HomeController.cs index 5183457e83..952d245c54 100644 --- a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Controllers/HomeController.cs +++ b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Controllers/HomeController.cs @@ -14,9 +14,11 @@ public IActionResult Index() var qrCodes = new Dictionary { { "Basic String", GenerateQRCodeString() }, + { "SVG", GenerateQRCodeSvg() }, { "URL", GenerateQRCodeURL() }, { "Phone Number", GenerateQRCodePhoneNumber() }, - { "Custom", GenerateQRCodeCustom() } + { "Custom", GenerateQRCodeCustom() }, + { "Branded", GenerateQRCodeBranded() } }; var model = new HomeModel(qrCodes); @@ -25,7 +27,7 @@ public IActionResult Index() } private string GenerateQRCodeCustom() - { + { const string key = "Custom"; var raw = db.Get(key); @@ -46,6 +48,15 @@ private string GenerateQRCodeString() return GeneratePng(qrCodeData); } + private string GenerateQRCodeSvg() + { + var qrCodeData = qrGenerator.CreateQrCode("Hello CodeMaze readers", QRCodeGenerator.ECCLevel.Q); + using var qrCode = new SvgQRCode(qrCodeData); + var svg = qrCode.GetGraphic(20); + + return $"data:image/svg+xml,{Uri.EscapeDataString(svg)}"; + } + private string GenerateQRCodeURL() { var qrCodeData = qrGenerator.CreateQrCode(new Url("https://www.code-maze.com")); @@ -60,7 +71,22 @@ private string GenerateQRCodePhoneNumber() return GeneratePng(qrCodeData); } + private string GenerateQRCodeBranded() + { + var qrCodeData = qrGenerator.CreateQrCode("Hello CodeMaze readers", QRCodeGenerator.ECCLevel.Q); + + return GeneratePngBranded(qrCodeData); + } + private static string GeneratePng(QRCodeData data) + { + using var qrCode = new PngByteQRCode(data); + var qrCodeImage = qrCode.GetGraphic(20); + + return $"data:image/png;base64,{Convert.ToBase64String(qrCodeImage)}"; + } + + private static string GeneratePngBranded(QRCodeData data) { using var qrCode = new PngByteQRCode(data); var qrCodeImage = qrCode.GetGraphic(20, [255, 0, 0], [0, 0, 139]); diff --git a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Program.cs b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Program.cs index 0ccfc22521..d54343d3b5 100644 --- a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Program.cs +++ b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Program.cs @@ -13,14 +13,16 @@ { app.UseExceptionHandler("/Home/Error"); } -app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); +app.MapStaticAssets(); + app.MapControllerRoute( name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); + pattern: "{controller=Home}/{action=Index}/{id?}") + .WithStaticAssets(); app.Run(); diff --git a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/QRCodeGeneratorWebSample.csproj b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/QRCodeGeneratorWebSample.csproj index e7f8d3a33c..6f2501ea30 100644 --- a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/QRCodeGeneratorWebSample.csproj +++ b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/QRCodeGeneratorWebSample.csproj @@ -1,13 +1,13 @@ - net8.0 + net10.0 enable enable - + diff --git a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/QrCodesDb.cs b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/QrCodesDb.cs index eec81fe275..9585b088fa 100644 --- a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/QrCodesDb.cs +++ b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/QrCodesDb.cs @@ -1,17 +1,15 @@ -using QRCoder; +using System.Collections.Concurrent; +using QRCoder; namespace QRCodeGeneratorWebSample; public class QrCodesDb { - private readonly Dictionary _qrCodes = []; + private readonly ConcurrentDictionary _qrCodes = new(); public void Add(string key, QRCodeData data) { - if (!_qrCodes.ContainsKey(key)) - { - _qrCodes.Add(key, data.GetRawData(QRCodeData.Compression.Uncompressed)); - } + _qrCodes.TryAdd(key, data.GetRawData(QRCodeData.Compression.Uncompressed)); } public byte[]? Get(string key) diff --git a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Views/Home/Index.cshtml b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Views/Home/Index.cshtml index 1ee4bbc12f..842e426aff 100644 --- a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Views/Home/Index.cshtml +++ b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Views/Home/Index.cshtml @@ -1,4 +1,4 @@ -@model HomeModel; +@model HomeModel
@foreach (var qr in Model.QRCodes) @@ -6,5 +6,5 @@

@qr.Key

- } + }
diff --git a/dotnet-client-libraries/QRCoder/Tests/QRCodeGeneratorWebSampleUnitTest.cs b/dotnet-client-libraries/QRCoder/Tests/QRCodeGeneratorWebSampleUnitTest.cs index ce1b393a22..72b98c38f7 100644 --- a/dotnet-client-libraries/QRCoder/Tests/QRCodeGeneratorWebSampleUnitTest.cs +++ b/dotnet-client-libraries/QRCoder/Tests/QRCodeGeneratorWebSampleUnitTest.cs @@ -6,27 +6,65 @@ namespace Tests; public class QRCodeGeneratorWebSampleUnitTest { - [Fact] - public void GivenARequest_WhenCallingIndex_ThenTheControllerRendersAViewWithQrCodes() + private static HomeModel RenderIndex() { - // Arrange. var db = new QrCodesDb(); var controller = new HomeController(db); - // Act. var viewResult = controller.Index() as ViewResult; - // Assert. Assert.NotNull(viewResult); var model = viewResult.Model as HomeModel; Assert.NotNull(model); + + return model; + } + + [Fact] + public void GivenARequest_WhenCallingIndex_ThenTheControllerRendersAViewWithQrCodes() + { + // Act. + var model = RenderIndex(); + + // Assert. Assert.NotNull(model.QRCodes); Assert.NotEmpty(model.QRCodes); - foreach (var qrCode in from expectedKey in new[] { "Basic String", "URL", "Phone Number", "Custom" } + foreach (var qrCode in from expectedKey in new[] { "Basic String", "SVG", "URL", "Phone Number", "Custom", "Branded" } let qrCode = model.QRCodes[expectedKey] select qrCode) { Assert.NotNull(qrCode); } } -} \ No newline at end of file + + [Fact] + public void GivenARequest_WhenCallingIndex_ThenThePngRendererProducesARealPng() + { + // Arrange. + const string prefix = "data:image/png;base64,"; + + // Act. + var dataUri = RenderIndex().QRCodes["Basic String"]; + + // Assert. + Assert.StartsWith(prefix, dataUri); + var bytes = Convert.FromBase64String(dataUri[prefix.Length..]); + Assert.Equal(new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, bytes[..8]); + } + + [Fact] + public void GivenARequest_WhenCallingIndex_ThenTheSvgRendererProducesAnSvgDocument() + { + // Arrange. + const string prefix = "data:image/svg+xml,"; + + // Act. + var dataUri = RenderIndex().QRCodes["SVG"]; + + // Assert. + Assert.StartsWith(prefix, dataUri); + var svg = Uri.UnescapeDataString(dataUri[prefix.Length..]); + Assert.Contains("", svg); + } +} diff --git a/dotnet-client-libraries/QRCoder/Tests/Tests.csproj b/dotnet-client-libraries/QRCoder/Tests/Tests.csproj index 684a5ffc7e..d64c3ec944 100644 --- a/dotnet-client-libraries/QRCoder/Tests/Tests.csproj +++ b/dotnet-client-libraries/QRCoder/Tests/Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net10.0 enable enable @@ -10,10 +10,10 @@ - - - - + + + + From 3cf89bd4bbffb86add71ea41f7e38419075c04d8 Mon Sep 17 00:00:00 2001 From: Vladimir Pecanac Date: Sun, 11 Oct 2026 11:05:38 +0200 Subject: [PATCH 2/2] QRCoder: basic string matches the article screenshots --- .../QRCodeGeneratorWebSample/Controllers/HomeController.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Controllers/HomeController.cs b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Controllers/HomeController.cs index 952d245c54..5d47fd08a7 100644 --- a/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Controllers/HomeController.cs +++ b/dotnet-client-libraries/QRCoder/QRCodeGeneratorWebSample/Controllers/HomeController.cs @@ -43,14 +43,14 @@ private string GenerateQRCodeCustom() private string GenerateQRCodeString() { - var qrCodeData = qrGenerator.CreateQrCode("Hello CodeMaze readers", QRCodeGenerator.ECCLevel.Q); + var qrCodeData = qrGenerator.CreateQrCode("Hello CodeMaze readers :)", QRCodeGenerator.ECCLevel.Q); return GeneratePng(qrCodeData); } private string GenerateQRCodeSvg() { - var qrCodeData = qrGenerator.CreateQrCode("Hello CodeMaze readers", QRCodeGenerator.ECCLevel.Q); + var qrCodeData = qrGenerator.CreateQrCode("Hello CodeMaze readers :)", QRCodeGenerator.ECCLevel.Q); using var qrCode = new SvgQRCode(qrCodeData); var svg = qrCode.GetGraphic(20); @@ -73,7 +73,7 @@ private string GenerateQRCodePhoneNumber() private string GenerateQRCodeBranded() { - var qrCodeData = qrGenerator.CreateQrCode("Hello CodeMaze readers", QRCodeGenerator.ECCLevel.Q); + var qrCodeData = qrGenerator.CreateQrCode("Hello CodeMaze readers :)", QRCodeGenerator.ECCLevel.Q); return GeneratePngBranded(qrCodeData); }