{"record":{"id":"52e0ec746a5b49ea","repo":"JeffreySu/WeiXinMPSDK","slug":"appkey-xpayapi","errorCode":null,"errorMessage":"appKey","messagePattern":"appKey","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/AdvancedAPIs/XPay/XPayApi.cs","lineNumber":1281,"sourceCode":"            }, accessTokenOrAppId);\n        }\n        #endregion\n\n        #region 扩展方法\n        /// <summary>\n        /// 生成pay_sig\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"appKey\"></param>\n        /// <param name=\"uri\">例：/xpay/query_user_balance</param>\n        /// <param name=\"data\"></param>\n        /// <returns></returns>\n        /// <exception cref=\"System.ArgumentNullException\"></exception>\n        public static string GeneratePaySign<T>(string appKey, string uri, T data)\n        {\n            if (string.IsNullOrWhiteSpace(appKey))\n            {\n                throw new ArgumentNullException(\"appKey\");\n            }\n            if (string.IsNullOrWhiteSpace(uri))\n            {\n                throw new ArgumentNullException(\"uri\");\n            }\n            if (data == null)\n            {\n                throw new ArgumentNullException(\"data\");\n            }\n\n            var signData = JsonConvert.SerializeObject(data);\n            var rawData = $\"{uri}&{signData}\";\n\n            var keyBytes = Encoding.UTF8.GetBytes(appKey);\n            var dataBytes = Encoding.UTF8.GetBytes(rawData);\n            using (var hmac = new HMACSHA256(keyBytes))\n            {\n                var hashBytes = hmac.ComputeHash(dataBytes);","sourceCodeStart":1263,"sourceCodeEnd":1299,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/AdvancedAPIs/XPay/XPayApi.cs#L1263-L1299","documentation":"XPayApi.GeneratePaySign (WeChat Mini Game virtual payment) throws ArgumentNullException when the appKey parameter is null, empty, or whitespace. The appKey is required as the HMAC signing key for the pay-sign computation.","triggerScenarios":"Calling XPayApi.GeneratePaySign(data, uri) with an appKey string that is null/empty — e.g. the key was never loaded from configuration or the config value is blank.","commonSituations":"appsettings/config file missing the XPay appKey entry; environment variable not set in the deployment environment; developer passes the wrong variable (appId instead of appKey).","solutions":["Supply a non-empty appKey from your configuration (微信小程序虚拟支付 Key)","Add a startup config check that fails fast if the XPay appKey is missing","Verify the config source actually populated the value (env var name, config section)"],"exampleFix":"// before\nvar sign = XPayApi.GeneratePaySign(null, uri, data);\n// after\nvar sign = XPayApi.GeneratePaySign(_options.XPayAppKey, uri, data); // _options.XPayAppKey validated non-empty at startup","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(appKey)) throw new InvalidOperationException(\"XPay appKey is not configured\");","typeGuard":null,"tryCatchPattern":"try { return XPayApi.GeneratePaySign(appKey, uri, data); }\ncatch (ArgumentNullException ex) { logger.LogError(ex, \"XPay signing input missing\"); throw new ConfigurationErrorsException(\"XPay appKey/uri/data invalid\", ex); }","preventionTips":["Validate XPay configuration at application startup","Store the appKey in a validated options class with [Required] attributes","Use IOptions validation so blank keys fail at boot, not at request time"],"tags":["wxopen","xpay","argument-null","signing"],"backgroundTag":"null-argument","analyzedSha":"be573f6f94bdbf718dd5f6cdecb137fbc7ff651e","analyzedAt":"2026-09-12T10:01:50.733Z","contentChangedAt":"2026-09-12T10:01:50.733Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}