{"record":{"id":"cd220f15f239ecbd","repo":"babalae/better-genshin-impact","slug":"serverchan-sendkey","errorCode":null,"errorMessage":"ServerChan SendKey为空","messagePattern":"ServerChan SendKey为空","errorType":"validation","errorClass":"NotifierException","httpStatus":null,"severity":"warning","filePath":"BetterGenshinImpact/Service/Notifier/ServerChanNotifier.cs","lineNumber":33,"sourceCode":"public class ServerChanNotifier : INotifier\n{\n    public string Name { get; set; } = \"ServerChan\";\n\n    private readonly HttpClient _httpClient;\n    private readonly string _sendKey;\n\n\n    public ServerChanNotifier(HttpClient httpClient, string sendKey)\n    {\n        _httpClient = httpClient;\n        _sendKey = sendKey;\n    }\n\n    public async Task SendAsync(BaseNotificationData content)\n    {\n        if (string.IsNullOrEmpty(_sendKey))\n        {\n            throw new NotifierException(\"ServerChan SendKey为空\");\n        }\n\n        try\n        {\n            // 获取正确的API URL\n            string apiUrl = GetServerChanApiUrl(_sendKey);\n\n            // 生成通知标题和内容\n            string title = $\"BetterGI·更好的原神\";\n            string desp = GenerateDescription(content);\n\n            // 准备表单数据\n            var postData = $\"title={Uri.EscapeDataString(title)}&desp={Uri.EscapeDataString(desp)}\";\n\n            // 创建请求\n            var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);\n            request.Content = new StringContent(postData, Encoding.UTF8, \"application/x-www-form-urlencoded\");\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/Service/Notifier/ServerChanNotifier.cs#L15-L51","documentation":"ServerChanNotifier.SendAsync rejects an empty _sendKey (passed to the constructor) before building the API URL, because the send key is the path credential for both sctapi.ftqq.com and the ft07.com push endpoints.","triggerScenarios":"ServerChanNotifier constructed with sendKey=\"\" or null; the line-31 IsNullOrEmpty(_sendKey) guard fires.","commonSituations":"User enabled ServerChan but never pasted a SendKey; key cleared during settings reset; SCT vs SCTP2024 migration removed the old key.","solutions":["Obtain a SendKey from ServerChan (sct.ftqq.com) or ServerChanTurbo (ft07.com) and save it in settings.","Gate notifier construction/registration on a non-empty key.","Add settings UI validation that blocks enabling the channel without a key."],"exampleFix":"// before\nvar n = new ServerChanNotifier(httpClient, sendKey);\n\n// after\nif (string.IsNullOrWhiteSpace(sendKey))\n    throw new InvalidOperationException(\"ServerChan SendKey must be configured before constructing the notifier.\");\nvar n = new ServerChanNotifier(httpClient, sendKey);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(sendKey))\n    throw new InvalidOperationException(\"Configure a ServerChan SendKey before sending.\");","typeGuard":"static bool IsServerChanConfigured(string sendKey) => !string.IsNullOrWhiteSpace(sendKey);","tryCatchPattern":"try { await serverChanNotifier.SendAsync(data); }\ncatch (NotifierException ex) when (ex.Message.Contains(\"SendKey为空\"))\n{ /* prompt user to paste SendKey, no retry */ }","preventionTips":["Block enabling ServerChan until a SendKey is entered.","Trim whitespace from the key on save."],"tags":["serverchan","config","validation","notifier"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}