{"record":{"id":"1f688a9b8abaad6a","repo":"JeffreySu/WeiXinMPSDK","slug":"data-xpayapi","errorCode":null,"errorMessage":"data","messagePattern":"data","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":1289,"sourceCode":"        /// <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);\n                return BitConverter.ToString(hashBytes).Replace(\"-\", \"\").ToLower();\n            }\n        }\n\n        /// <summary>\n        /// 生成signature\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>","sourceCodeStart":1271,"sourceCodeEnd":1307,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/AdvancedAPIs/XPay/XPayApi.cs#L1271-L1307","documentation":"XPayApi.GeneratePaySign builds the request signature for WeChat mini-game virtual-payment (xpay) endpoints by serializing the request payload T data and HMAC-signing it with appKey and uri. It throws ArgumentNullException when data is null: there is no payload to sign, so no valid signature can be produced. The method explicitly documents ArgumentNullException; the offending input here is the data object, which must be non-null alongside appKey and uri for signature generation.","triggerScenarios":"Calling GeneratePaySign(appKey, uri, null) — usually the result of an upstream query that produced null and was passed straight through to the signing call.","commonSituations":"Upstream order/balance query returned null and the code did not check before signing; generic type T instantiated with a null reference.","solutions":["Check the data object for null before calling GeneratePaySign","Fail earlier in the flow when the payload could not be built","Construct a valid payload object even when upstream data is absent"],"exampleFix":"// before\nvar sign = XPayApi.GeneratePaySign(appKey, uri, order); // order may be null\n// after\nif (order == null) throw new InvalidOperationException(\"order payload missing\");\nvar sign = XPayApi.GeneratePaySign(appKey, uri, order);","handlingStrategy":"validation","validationCode":"if (data == null) throw new InvalidOperationException(\"XPay payload must not be null\");","typeGuard":"bool HasPayload<T>(T data) => data is not null;","tryCatchPattern":"try { return XPayApi.GeneratePaySign(appKey, uri, data); }\ncatch (ArgumentNullException ex) { logger.LogError(ex, \"XPay data payload missing\"); throw; }","preventionTips":["Null-check upstream query results before signing","Never pass through possibly-null objects into signing helpers","Cover the signing path with tests including empty upstream results"],"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"}