Hello,各位小伙伴们,这篇文章主要给大家分享近期开发所遇到的一个由于环境权限差异问题而引发的一个BUG。希望能给我们后续开发提前预警。
一、需求:应用程序现需要一个持久化按日递增流水号生成器(2026042100001),用这个工具所生成的流水号去调接口。
二、分析:我决定在exe根目录下新建一个txt文件来存储生成的流水号(日期+序号),然后每次生成完新的流水号就同步更新这个txt文件。
三、问题代码:
using System; using System.IO; namespace NFS.Models.Common.Custom { public static class PersistentSerialNumberGenerator { private static readonly object _lockObj = new object(); // 计数存储文件路径(可自定义) private static readonly string _configPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SerialConfig.txt"); private static DateTime today; public static string Generate(DateTime? processingDate) { lock (_lockObj) { today = processingDate ?? DateTime.Today; string todayStr = today.ToString("yyyyMMdd"); // 初始化:读取文件中的历史日期和计数 var config = ReadConfig(); string lastDate = config.Item1; int count = config.Item2; // 跨天判断:重置计数 if (lastDate != todayStr) { count = 1; lastDate = todayStr; } // 生成流水号 string sn = $"{todayStr}{count:D5}"; // 计数+1并保存到文件 WriteConfig(lastDate, count + 1); return sn; } } // 读取配置:上次日期+当前计数 private static Tuple<string, int> ReadConfig() { try { if (File.Exists(_configPath)) { string[] lines = File.ReadAllLines(_configPath); return Tuple.Create(lines[0], int.Parse(lines[1])); } } catch { } return Tuple.Create(today.ToString("yyyyMMdd"), 1); } // 写入配置:保存日期和计数 private static void WriteConfig(string date, int count) { File.WriteAllLines(_configPath, new[] { date, count.ToString() }); } } }调用:
TransNumber = PersistentSerialNumberGenerator.Generate(processDate) //需要把当前时间给这个方法问题:这里作者就没有考虑到自己开发环境与软件生产环境的权限差异问题。作者在本地开发环境中,拥有对exe根目录文件夹完全控制(Full control)权,所以读取写入(覆盖)是完全没问题的且不会报错的,但是生产环境就只是一个只读的权限,这也就导致这个流水号生成器在开发环境是不会报错的,但是一放到只有只读权限的生产环境时,就会报错。
更可笑的是,作者拿到生产环境的备份库后,在自己开发环境调试程序的时候,由于权限足够,是不会报错的,这也就让作者很长时间定位不到问题,所以这个BUG耗费了作者小一天的时间。
解决方案:
临时解决方案:勾选完全控制(Full control),或者是写入(Write)权限
标准解决方案:
//方案一,先删除再写入,而不是直接覆盖,因为覆盖文件就需要Windows的写入权限 private static void WriteConfig(string date, int count) { string fullPath = _configPath; // 只读文件夹安全写入 if (File.Exists(fullPath)) File.Delete(fullPath); File.WriteAllLines(fullPath, new[] { date, count.ToString() }); } //方案二,再exe根目录下同级建一个文件夹来放txt文件,因为Windows新建文件夹默认不只读,一句话总结:父文件夹权限不影响子文件夹,新建的子文件夹完全自由读写 private static void WriteConfig(string date, int count) { // 依然跟着EXE走,打包复制一起走 string configDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config"); if (!Directory.Exists(configDir)) Directory.CreateDirectory(configDir); _configPath = Path.Combine(configDir, "SerialConfig.txt"); File.WriteAllLines(_configPath , new[] { date, count.ToString() }); }今天的分享就到这了,拜拜~