using FileShare_Common.Core; using FileShare_Services.Core; using Microsoft.Extensions.Configuration; using QRCoder; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; namespace FileShare_Services.Services.QrCode { /// /// 二维码生成服务,获取局域网 IP 并生成 PNG 格式的访问二维码。 /// public sealed class QrCodeService(IConfiguration configuration) : IQrCodeService { /// public Task GenerateQrCodeAsync(ServiceEndpointContext ctx) { var ip = GetLanIpAddress(); if (ip is null) throw new InvalidOperationException("无法获取局域网IP地址"); var port = int.TryParse(configuration["Server:HttpPort"], out var p) ? p : 5206; var url = $"http://{ip}:{port}"; var base64 = GeneratePngBase64(url); return Task.FromResult(ResponseHelper.Ok(new QrCodeResponse(url, base64))); } /// /// 使用 QRCoder 库生成指定内容的二维码,输出为 Base64 编码的 PNG data URI。 /// /// 二维码编码内容。 /// data URI 格式的 Base64 PNG 字符串。 private static string GeneratePngBase64(string content) { using var generator = new QRCodeGenerator(); using var data = generator.CreateQrCode(content, QRCodeGenerator.ECCLevel.Q); using var png = new PngByteQRCode(data); var bytes = png.GetGraphic(20); return $"data:image/png;base64,{Convert.ToBase64String(bytes)}"; } /// /// 获取本机第一个可用的局域网 IPv4 地址,排除回环地址和 APIPA 地址(169.254.x.x)。 /// /// 局域网 IP 地址字符串,无可用地址时返回 null。 private static string? GetLanIpAddress() { return NetworkInterface.GetAllNetworkInterfaces() .Where(ni => ni.OperationalStatus == OperationalStatus.Up && ni.NetworkInterfaceType != NetworkInterfaceType.Loopback) .SelectMany(ni => ni.GetIPProperties().UnicastAddresses) .Select(ua => ua.Address) .FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip) && !ip.ToString().StartsWith("169.254")) ?.ToString(); } } }