- 所有空 catch 块补全日志记录,统一使用 Serilog/AppLog - 按场景分级:Error(意外失败)、Warning(次要问题)、Information(预期内) - 端口 HttpPort/HttpsPort 抽离到 appsettings.json Server 配置节 - QrCodeService 通过 IConfiguration 读取端口,消除硬编码 - 前端通过 Vite proxy 转发 /api,http.ts 统一使用 origin 地址 - 移除所有 Debug.WriteLine 和 Serilog.Log.Debug 日志 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
62 lines
2.6 KiB
C#
62 lines
2.6 KiB
C#
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
|
||
{
|
||
/// <summary>
|
||
/// 二维码生成服务,获取局域网 IP 并生成 PNG 格式的访问二维码。
|
||
/// </summary>
|
||
public sealed class QrCodeService(IConfiguration configuration) : IQrCodeService
|
||
{
|
||
/// <inheritdoc />
|
||
public Task<object?> 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<object?>(ResponseHelper.Ok(new QrCodeResponse(url, base64)));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 使用 QRCoder 库生成指定内容的二维码,输出为 Base64 编码的 PNG data URI。
|
||
/// </summary>
|
||
/// <param name="content">二维码编码内容。</param>
|
||
/// <returns>data URI 格式的 Base64 PNG 字符串。</returns>
|
||
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)}";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取本机第一个可用的局域网 IPv4 地址,排除回环地址和 APIPA 地址(169.254.x.x)。
|
||
/// </summary>
|
||
/// <returns>局域网 IP 地址字符串,无可用地址时返回 null。</returns>
|
||
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();
|
||
}
|
||
}
|
||
}
|