{"record":{"id":"3a99b31e0525a18d","repo":"JeffreySu/WeiXinMPSDK","slug":"appid-0-accesstokencontainer-register","errorCode":null,"errorMessage":"此appId（{0}）尚未注册，请先使用AccessTokenContainer.Register完成注册（全局执行一次即可）！","messagePattern":"此appId（(.+?)）尚未注册，请先使用AccessTokenContainer\\.Register完成注册（全局执行一次即可）！","errorType":"exception","errorClass":"UnRegisterAppIdException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.MP/Senparc.Weixin.MP/Containers/AccessTokenContainer.cs","lineNumber":204,"sourceCode":"        /// <param name=\"appId\"></param>\n        /// <param name=\"getNewToken\">是否强制重新获取新的Token</param>\n        /// <returns></returns>\n        public static string GetAccessToken(string appId, bool getNewToken = false)\n        {\n            return GetAccessTokenResult(appId, getNewToken).access_token;\n        }\n\n        /// <summary>\n        /// 获取可用AccessTokenResult对象\n        /// </summary>\n        /// <param name=\"appId\"></param>\n        /// <param name=\"getNewToken\">是否强制重新获取新的Token</param>\n        /// <returns></returns>\n        public static AccessTokenResult GetAccessTokenResult(string appId, bool getNewToken = false)\n        {\n            if (!CheckRegistered(appId))\n            {\n                throw new UnRegisterAppIdException(appId, string.Format(\"此appId（{0}）尚未注册，请先使用AccessTokenContainer.Register完成注册（全局执行一次即可）！\", appId));\n            }\n\n            var accessTokenBag = TryGetItem(appId);\n\n            using (Cache.BeginCacheLock(LockResourceName, appId))//同步锁\n            {\n                accessTokenBag = TryGetItem(appId);//获锁后重新读取，避免使用分布式缓存中的旧副本重复刷新\n                if (getNewToken || accessTokenBag.AccessTokenExpireTime <= SystemTime.Now)\n                {\n                    //已过期，重新获取\n                    accessTokenBag.AccessTokenResult = CommonApi.GetToken(accessTokenBag.AppId, accessTokenBag.AppSecret);\n                    accessTokenBag.AccessTokenExpireTime = ApiUtility.GetExpireTime(accessTokenBag.AccessTokenResult.expires_in);\n                    Update(accessTokenBag, null);//更新到缓存\n                }\n            }\n            return accessTokenBag.AccessTokenResult;\n        }\n","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.MP/Senparc.Weixin.MP/Containers/AccessTokenContainer.cs#L186-L222","documentation":"GetAccessTokenResult throws UnRegisterAppIdException when CheckRegistered(appId) is false, meaning the appId was never registered in the AccessTokenContainer's cache. Senparc.Weixin requires a one-time AccessTokenContainer.Register(appId, appSecret) call (typically at application startup) before any token can be retrieved for that appId.","triggerScenarios":"Calling AccessTokenContainer.GetAccessToken(appId) or GetAccessTokenResult(appId) for an appId that was never registered via AccessTokenContainer.Register/RegisterAsync, or whose registration was lost because the cache was cleared/reset.","commonSituations":"Forgetting the startup Register call; registering in a process different from the one consuming the token (e.g. registering in a background worker, consuming in the web app); multi-tenant apps registering only the first tenant; cache restart (server reboot with memory cache) wiping registrations when using a non-persistent cache.","solutions":["Call AccessTokenContainer.Register(appId, appSecret) once at application startup (e.g. in Startup/Program.cs) for every appId you will use.","Verify the appId string exactly matches the one registered (case/whitespace).","If you use Redis or another distributed cache, ensure the registration container shares the same cache domain as the consumer process.","Log the registered appIds at startup and compare against the failing one to catch typos or missing tenants."],"exampleFix":"// before\nvar token = AccessTokenContainer.GetAccessToken(appId); // throws UnRegisterAppIdException\n// after\n// at startup:\nAccessTokenContainer.Register(appId, appSecret);\n// then:\nvar token = AccessTokenContainer.GetAccessToken(appId);","handlingStrategy":"try-catch","validationCode":"if (!AccessTokenContainer.CheckRegistered(appId))\n{\n    AccessTokenContainer.Register(appId, appSecret);\n}","typeGuard":"bool IsTokenRegistered(string appId) => AccessTokenContainer.CheckRegistered(appId);","tryCatchPattern":"try\n{\n    var token = AccessTokenContainer.GetAccessToken(appId);\n}\ncatch (UnRegisterAppIdException ex)\n{\n    _logger.LogError(ex, \"appId {AppId} not registered in AccessTokenContainer; call Register at startup.\", appId);\n    AccessTokenContainer.Register(appId, _secrets.Get(appId));\n    // retry once if appropriate\n}","preventionTips":["Register every appId in a single, centralized startup routine (Program.cs/Startup.cs).","Keep registration and consumption in the same process and cache domain.","Use a distributed cache (Redis) so registrations survive restarts and multi-instance deployments.","Add a health check that verifies CheckRegistered(appId) for all configured appIds."],"tags":["csharp","weixin","unregistered-appid","configuration"],"backgroundTag":"unregistered-appid","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"}