{"record":{"id":"4837e55e0b007657","repo":"JeffreySu/WeiXinMPSDK","slug":"api-tenpaynotifyhandler","errorCode":null,"errorMessage":"品牌 API 密钥不能为空。","messagePattern":"品牌 API 密钥不能为空。","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/HttpHandlers/TenPayNotifyHandler.cs","lineNumber":354,"sourceCode":"        }\n\n        /// <summary>\n        /// 使用品牌 API 专用密钥解密通知资源，并使用品牌关联的微信支付公钥验签。\n        /// </summary>\n        /// <typeparam name=\"T\">解密后的强类型通知模型。</typeparam>\n        /// <param name=\"brandApiKey\">品牌 API 密钥。</param>\n        /// <param name=\"brandApiCredentials\">品牌 API 鉴权凭据，其中包含回调验签所需的微信支付公钥。</param>\n        /// <param name=\"nonce\">加密随机串；为空时读取通知资源中的值。</param>\n        /// <param name=\"associatedData\">附加数据；为空时读取通知资源中的值。</param>\n        /// <returns>验签并解密后的品牌通知。</returns>\n        public Task<T> DecryptBrandGetObjectAsync<T>(string brandApiKey,\n            TenPayBrandApiCredentials brandApiCredentials,\n            string nonce = null, string associatedData = null)\n            where T : ReturnJsonBase, new()\n        {\n            if (string.IsNullOrWhiteSpace(brandApiKey))\n            {\n                throw new ArgumentException(\"品牌 API 密钥不能为空。\",\n                    nameof(brandApiKey));\n            }\n\n            _ = brandApiCredentials ?? throw new ArgumentNullException(\n                nameof(brandApiCredentials));\n            var resource = NotifyRequest?.resource ?? throw new InvalidDataException(\n                \"通知正文中缺少加密资源 resource。\");\n\n            var wechatpayTimestamp =\n                _httpContext.Request.Headers?[\"Wechatpay-Timestamp\"].ToString();\n            var wechatpayNonce =\n                _httpContext.Request.Headers?[\"Wechatpay-Nonce\"].ToString();\n            var wechatpaySignature =\n                _httpContext.Request.Headers?[\"Wechatpay-Signature\"].ToString();\n            var wechatpaySerial =\n                _httpContext.Request.Headers?[\"Wechatpay-Serial\"].ToString();\n\n            if (!string.Equals(wechatpaySerial,","sourceCodeStart":336,"sourceCodeEnd":372,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/HttpHandlers/TenPayNotifyHandler.cs#L336-L372","documentation":"DecryptBrandGetObjectAsync decrypts WeChat Pay brand-notification resources (AES-GCM) and verifies the callback signature. It throws when brandApiKey is null/empty: without the brand-specific API key the encrypted resource cannot be decrypted, so processing the notification is impossible. The offending input is the brandApiKey parameter; callers must supply the key configured for the brand in the WeChat Pay merchant platform.","triggerScenarios":"Calling DecryptBrandGetObjectAsync with null/empty brandApiKey while decrypting a brand notification resource.","commonSituations":"Brand API key not stored in configuration, copying generic V3 decryption sample code that omits the brand key, or key name mismatch in appsettings.","solutions":["Provide the Brand API v3 key obtained from the WeChat merchant platform (品牌接口密钥) when calling the method","Load the brand API key from configuration and validate it at startup","Guard the call: only invoke DecryptBrandGetObjectAsync when the key is present","Distinguish the brand API key from the merchant APIv3 key — ensure the right credential is bound"],"exampleFix":"// before\nawait handler.DecryptBrandGetObjectAsync<T>(null, credentials);\n// after\nawait handler.DecryptBrandGetObjectAsync<T>(brandApiKey: config[\"TenpayV3:BrandApiKey\"], credentials);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(brandApiKey))\n    throw new InvalidOperationException(\"品牌 API 密钥未配置。\");","typeGuard":"bool HasBrandApiKey(string? key) => !string.IsNullOrWhiteSpace(key);","tryCatchPattern":"try { var obj = await handler.DecryptBrandGetObjectAsync<T>(brandApiKey, creds); }\ncatch (ArgumentException ex) when (ex.ParamName == nameof(brandApiKey)) { logger.LogError(ex, \"品牌 API 密钥缺失\"); }","preventionTips":["Store the brand API key in secure configuration (not code)","Load and validate all TenpayV3 keys at startup","Don't confuse brand API key with merchant APIv3 key"],"tags":["missing-api-key","tenpay","decryption"],"backgroundTag":"missing-api-key","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"}