JeffreySu/WeiXinMPSDK · error · InvalidDataException
通知正文中缺少加密资源 resource。
Error message
通知正文中缺少加密资源 resource。
What it means
The decrypted resource must be present in the notification JSON (NotifyRequest.resource); when the parsed body has no resource object, DecryptBrandGetObjectAsync throws InvalidDataException "通知正文中缺少加密资源 resource。". This indicates the notification body is not the expected encrypted brand resource payload.
Solutions
- Verify the notification event_type actually carries an encrypted resource before decrypting
- Re-read the body with EnableBuffering so deserialization isn't operating on an empty stream
- Return 200/OK handling for notifications without resource instead of treating them as brand data
- Log NotifyRequest JSON when resource is missing to diagnose the payload shape
- Check that the callback URL is only registered for events that include encrypted resources
Example fix
// before
var obj = await handler.DecryptBrandGetObjectAsync<T>(apiKey, creds);
// after
if (handler.NotifyRequest?.resource == null)
{
return Ok(); // 非加密资源通知,直接确认
}
var obj = await handler.DecryptBrandGetObjectAsync<T>(apiKey, creds); Defensive patterns
Strategy: try-catch
Validate before calling
if (handler.NotifyRequest?.resource is null) return Ok(); // 非加密资源通知
Type guard
bool HasEncryptedResource(NotificationRequest? r) => r?.resource is not null;
Try / catch
try { var obj = await handler.DecryptBrandGetObjectAsync<T>(apiKey, creds); }
catch (InvalidDataException ex) when (ex.Message.Contains("缺少加密资源"))
{ logger.LogWarning(ex, "通知缺少 resource"); return Ok(); } Prevention
- Check event_type before decryption
- Enable request body buffering to avoid empty re-reads
- Log full notification JSON when resource is absent to detect event routing mistakes
When it happens
Trigger: Notification body deserialized into NotifyRequest without a resource field — wrong event type, empty/failed POST body read, or an ACK/verification request routed into the decrypt method.
Common situations: WeChat sends non-encrypted notifications (e.g. duplicate-notify ACKs) to the same endpoint, malformed JSON, or the body was consumed before deserialization.
Related errors
- 品牌 API 密钥不能为空。
- brandApiCredentials
- WeixinPayInfoCollection尚未注册Partner:
- 未获取到用于加密收款用户姓名的微信支付公钥或平台证书。
- 当 为 时, 必填!
AI-assisted analysis of JeffreySu/WeiXinMPSDK@be573f6f94 (2026-09-12).
Data as JSON: /api/errors/5c1a683599a05db1.
Report an issue: GitHub.
Appendix: source
Thrown at src/Senparc.Weixin.TenPay/Senparc.Weixin.TenPayV3/HttpHandlers/TenPayNotifyHandler.cs:360
/// <param name="brandApiKey">品牌 API 密钥。</param>
/// <param name="brandApiCredentials">品牌 API 鉴权凭据,其中包含回调验签所需的微信支付公钥。</param>
/// <param name="nonce">加密随机串;为空时读取通知资源中的值。</param>
/// <param name="associatedData">附加数据;为空时读取通知资源中的值。</param>
/// <returns>验签并解密后的品牌通知。</returns>
public Task<T> DecryptBrandGetObjectAsync<T>(string brandApiKey,
TenPayBrandApiCredentials brandApiCredentials,
string nonce = null, string associatedData = null)
where T : ReturnJsonBase, new()
{
if (string.IsNullOrWhiteSpace(brandApiKey))
{
throw new ArgumentException("品牌 API 密钥不能为空。",
nameof(brandApiKey));
}
_ = brandApiCredentials ?? throw new ArgumentNullException(
nameof(brandApiCredentials));
var resource = NotifyRequest?.resource ?? throw new InvalidDataException(
"通知正文中缺少加密资源 resource。");
var wechatpayTimestamp =
_httpContext.Request.Headers?["Wechatpay-Timestamp"].ToString();
var wechatpayNonce =
_httpContext.Request.Headers?["Wechatpay-Nonce"].ToString();
var wechatpaySignature =
_httpContext.Request.Headers?["Wechatpay-Signature"].ToString();
var wechatpaySerial =
_httpContext.Request.Headers?["Wechatpay-Serial"].ToString();
if (!string.Equals(wechatpaySerial,
brandApiCredentials.WechatpayPublicKeyId,
StringComparison.Ordinal))
{
throw new InvalidOperationException(
"品牌 API 通知的微信支付公钥 ID 与配置不匹配。");
}View on GitHub (pinned to be573f6f94)