当前位置: 首页 > news >正文

【项目实战】在开发全局流水号生成器过程中,需考虑自己开发环境与软件生产环境的权限差异问题!

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() }); }

今天的分享就到这了,拜拜~

http://www.jsqmd.com/news/692927/

相关文章:

  • PyCaret:机器学习自动化工具的核心技术与实战应用
  • 终极指南:5分钟学会用genshin-fps-unlock突破《原神》60帧限制 [特殊字符]
  • Zed 编辑器小修小补:让 diff 颜色终于“说人话“了!
  • 2026年河南兔笼养殖设备采购指南:一站式建场方案对比评测 - 优质企业观察收录
  • Anthropic报告:AI帮得越多越焦虑,知识精英成内卷重灾区!
  • 齿轮箱零部件及其装配质检中的TVA技术突破(30)
  • 拆开一个手机看看:MEMS电容式加速度计是怎么让你玩赛车游戏不翻车的?
  • 3分钟极速上手:英雄联盟智能助手League Akari的终极使用指南
  • 泉州客多旧货回收:诏安餐饮设备回收价格 - LYL仔仔
  • 大语言模型文本扩展实战:自动生成个性化客服邮件与temperature参数调优(附代码)
  • 告别纸上谈兵:用Python+SUMO从零搭建你的第一个交通流仿真模型(附代码)
  • 打造专属知识管理中心:Obsidian个性化首页配置全攻略
  • 黑客攻防怎么学?收好这份黑客教程(保姆级通俗易懂)
  • 脉冲神经网络剪枝技术:SpikeNM框架解析与应用
  • 2025最新抖音H5商城源码|免登录版+演示站+代部署服务|亲测可用
  • 全国喷涂生产线/自动喷涂线厂家推荐指南:优质服务商深度解析 - 深度智识库
  • 2024年MathorCup C题:从数据预处理到排班优化的全链路建模实战
  • 全志A40i开发板USB-WiFi踩坑记:RTL8188FTV/FU驱动编译与配置保姆级教程
  • 18个月从“濒死”到启动IPO,象帝先凭技术与资本补血冲击国产GPU上市热潮
  • 金蝶KIS全系列安装包下载地址 KIS迷你版、KIS标准版、KIS专业版、KIS商贸版、KIS商贸钢材版、KIS云桌面、KIS财税王、KIS零售版、KIS教学版、KIS易记账、行政版、国际版、记账王
  • 如何用d2s-editor让你的暗黑破坏神2角色瞬间变身超级英雄?
  • 【Vercel实用Skill】web-design-guidelines 技能
  • 空间智能感知:多视角相机高精度无感定位技术方案:行业厘米级无感定位标杆方案・全域空间智能感知领先实践
  • 2026年转行进入网络安全领域薪资及工作安排与前景如何
  • 数据安全优先:企业级智能体私有化部署完整方案与最佳实践
  • 2026年河南养兔笼具与现代化兔场建设完全指南 - 优质企业观察收录
  • 告别数据缺失烦恼:手把手教你用SwatWeather为SWAT模型插补气象数据(附临洮站1970-2020年实战)
  • 山西安居搬家:太原专业的搬家搬迁公司找哪家 - LYL仔仔
  • 别再死记硬背了!用大白话+生活例子,5分钟搞懂BLP和Biba模型的核心区别
  • 齿轮箱零部件及其装配质检中的TVA技术突破(31)