JeffreySu/WeiXinMPSDK · error · UnRegisterAppIdException

此appId尚未注册,请先使用JsApiTicketContainer.Register完成注册(全局执行一次即可)!

Error message

此appId尚未注册,请先使用JsApiTicketContainer.Register完成注册(全局执行一次即可)!

What it means

GetJsApiTicketResult throws UnRegisterAppIdException when CheckRegistered(appId) reports the appId is not registered in JsApiTicketContainer. JS-API tickets use their own container, so an appId registered only in AccessTokenContainer is still unregistered here; a separate JsApiTicketContainer.Register call is required.

Solutions

  1. Call JsApiTicketContainer.Register(appId, appSecret) once at startup for every appId needing JS-API tickets.
  2. Register in BOTH containers if you need both access tokens and tickets.
  3. Ensure the appId matches exactly the one used at lookup.
  4. If tickets are only needed later, wrap retrieval with a registered-check or register lazily on first use.

Example fix

// before
var ticket = JsApiTicketContainer.GetJsApiTicket(appId); // throws: only AccessToken registered
// after
AccessTokenContainer.Register(appId, appSecret);
JsApiTicketContainer.Register(appId, appSecret); // required separately
var ticket = JsApiTicketContainer.GetJsApiTicket(appId);
Defensive patterns

Strategy: try-catch

Validate before calling

if (!JsApiTicketContainer.CheckRegistered(appId))
{
    JsApiTicketContainer.Register(appId, appSecret);
}

Type guard

bool IsTicketRegistered(string appId) => JsApiTicketContainer.CheckRegistered(appId);

Try / catch

try
{
    var ticket = JsApiTicketContainer.GetJsApiTicket(appId);
}
catch (UnRegisterAppIdException ex)
{
    _logger.LogError(ex, "appId {AppId} missing from JsApiTicketContainer registration.", appId);
    JsApiTicketContainer.Register(appId, _secrets.Get(appId));
}

Prevention

When it happens

Trigger: Calling JsApiTicketContainer.GetJsApiTicket(appId) or GetJsApiTicketResult(appId) without a prior JsApiTicketContainer.Register(appId, appSecret) for that appId.

Common situations: Developer assumes the AccessToken registration covers tickets (it does not); ticket registration call accidentally removed in a refactor; new appId added to token config but not the ticket registration list; container cache reset on restart with memory cache.

Related errors


AI-assisted analysis of JeffreySu/WeiXinMPSDK@be573f6f94 (2026-09-12). Data as JSON: /api/errors/57034d666b27a98a. Report an issue: GitHub.

Appendix: source

Thrown at src/Senparc.Weixin.MP/Senparc.Weixin.MP/Containers/JsApiTicketContainer.cs:182

        /// <param name="appId"></param>
        /// <param name="getNewTicket">是否强制重新获取新的Ticket</param>
        /// <returns></returns>
        public static string GetJsApiTicket(string appId, bool getNewTicket = false)
        {
            return GetJsApiTicketResult(appId, getNewTicket).ticket;
        }

        /// <summary>
        /// 获取可用Ticket
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="getNewTicket">是否强制重新获取新的Ticket</param>
        /// <returns></returns>
        public static JsApiTicketResult GetJsApiTicketResult(string appId, bool getNewTicket = false)
        {
            if (!CheckRegistered(appId))
            {
                throw new UnRegisterAppIdException(null, "此appId尚未注册,请先使用JsApiTicketContainer.Register完成注册(全局执行一次即可)!");
            }

            var jsApiTicketBag = TryGetItem(appId);
            using (Cache.BeginCacheLock(LockResourceName, appId))//同步锁
            {
                jsApiTicketBag = TryGetItem(appId);//获锁后重新读取并二次检查过期状态
                if (getNewTicket || jsApiTicketBag.JsApiTicketExpireTime <= SystemTime.Now)
                {
                    //已过期,重新获取
                    jsApiTicketBag.JsApiTicketResult = CommonApi.GetTicket(jsApiTicketBag.AppId, jsApiTicketBag.AppSecret);
                    jsApiTicketBag.JsApiTicketExpireTime = ApiUtility.GetExpireTime(jsApiTicketBag.JsApiTicketResult.expires_in);
                    Update(jsApiTicketBag, null);
                }
            }
            return jsApiTicketBag.JsApiTicketResult;
        }

        #endregion

View on GitHub (pinned to be573f6f94)