Windows服务中调用Telegram Bot静态布尔方法出现冻结无响应问题
问题:Windows服务调用静态布尔方法导致冻结,WinForms中运行正常
在Windows服务中调用静态布尔方法IsUserRegistered时,服务会冻结且无法处理任何请求;但该方法在WinForms应用中可正常执行,注释掉该方法调用后服务恢复正常,且服务内其他读取注册表的操作均无异常。怀疑是否JSON在异步方法中无法工作?
静态布尔方法代码
public static bool IsUserRegistered(long UserId) { List<TelegramUser> UserDb = new List<TelegramUser>(); string json = System.IO.File.ReadAllText(GlobalStrings.File_UserDB); UserDb = JsonSerializer.Deserialize<List<TelegramUser>>(json); TelegramUser selectedUser = UserDb.Find(u => u.ChatID == UserId); return selectedUser != null; }
Windows服务调用代码
static async Task OnMessage(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken) { bool UserOrGuest = false; if (update.Message is Message message) { UserOrGuest = Users.IsUserRegistered(6122562837); SendMessage(update.Message, "Registered: "+ UserOrGuest.ToString()); } }
原因分析与解决方案
问题并非JSON在异步方法中无法工作,核心原因是Windows服务的运行权限与文件路径不匹配:
- Windows服务默认以Local System账户运行,该账户对用户专属目录(如
C:\Users\XXX\...)无访问权限,若GlobalStrings.File_UserDB指向此类路径,服务会因权限不足卡在File.ReadAllText步骤,导致线程阻塞、服务冻结。 - 若使用相对路径,服务会默认读取系统目录(如
C:\Windows\System32),而非程序安装目录,引发文件找不到的问题,进而阻塞服务。
解决步骤
修正文件路径
确保GlobalStrings.File_UserDB指向服务有权访问的路径,比如程序安装目录或公共数据目录:// 获取服务程序的运行目录 string appDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); GlobalStrings.File_UserDB = Path.Combine(appDir, "userdb.json");或使用公共数据目录:
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "你的应用名", "userdb.json")配置服务权限
- 若必须使用特定路径,可修改服务的登录账户为拥有该路径访问权限的本地用户;
- 或给Local System账户添加目标文件/文件夹的读取权限。
添加异常捕获
在IsUserRegistered中加入异常处理,避免未处理异常导致服务阻塞,同时记录错误日志:public static bool IsUserRegistered(long UserId) { try { List<TelegramUser> UserDb = new List<TelegramUser>(); string json = System.IO.File.ReadAllText(GlobalStrings.File_UserDB); UserDb = JsonSerializer.Deserialize<List<TelegramUser>>(json); return UserDb.Any(u => u.ChatID == UserId); } catch (Exception ex) { // 写入Windows事件日志 EventLog.WriteEntry("你的服务名称", $"IsUserRegistered错误:{ex.Message}", EventLogEntryType.Error); return false; } }改用异步IO避免线程阻塞
将同步文件读取改为异步方法,避免在异步回调中阻塞线程池:public static async Task<bool> IsUserRegisteredAsync(long UserId) { try { string json = await System.IO.File.ReadAllTextAsync(GlobalStrings.File_UserDB); List<TelegramUser> UserDb = JsonSerializer.Deserialize<List<TelegramUser>>(json); return UserDb.Any(u => u.ChatID == UserId); } catch (Exception ex) { EventLog.WriteEntry("你的服务名称", $"IsUserRegisteredAsync错误:{ex.Message}", EventLogEntryType.Error); return false; } }调用时同步改为异步:
UserOrGuest = await Users.IsUserRegisteredAsync(6122562837);
内容的提问来源于stack exchange,提问作者waynemodz
相关产品推荐
相关产品推荐

