{"record":{"id":"fdfbb9655ade615b","repo":"JeffreySu/WeiXinMPSDK","slug":"un-register-alert-providertokencontainer","errorCode":null,"errorMessage":"UN_REGISTER_ALERT","messagePattern":"UN_REGISTER_ALERT","errorType":"exception","errorClass":"WeixinWorkException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.Work/Senparc.Weixin.Work/Containers/ProviderTokenContainer.cs","lineNumber":192,"sourceCode":"        /// <param name=\"getNewToken\">是否强制重新获取新的Token</param>\n        /// <returns></returns>\n        public static string GetToken(string corpId, string corpSecret, bool getNewToken = false)\n        {\n            return GetTokenResult(corpId, corpSecret, getNewToken).provider_access_token;\n        }\n\n        /// <summary>\n        /// 获取可用Token\n        /// </summary>\n        /// <param name=\"corpId\"></param>\n        /// <param name=\"corpSecret\"></param>\n        /// <param name=\"getNewToken\">是否强制重新获取新的Token</param>\n        /// <returns></returns>\n        public static ProviderTokenResult GetTokenResult(string corpId, string corpSecret, bool getNewToken = false)\n        {\n            if (!CheckRegistered(AccessTokenContainer.BuildingKey(corpId, corpSecret)))\n            {\n                throw new WeixinWorkException(UN_REGISTER_ALERT);\n            }\n\n            var shortKey = AccessTokenContainer.BuildingKey(corpId, corpSecret);\n            var providerTokenBag = TryGetItem(shortKey);\n            using (Cache.BeginCacheLock(LockResourceName, shortKey))\n            {\n                providerTokenBag = TryGetItem(shortKey);//获锁后重新读取并二次检查过期状态\n                if (getNewToken || providerTokenBag.ExpireTime <= SystemTime.Now)\n                {\n                    //已过期，重新获取\n                    providerTokenBag.ProviderTokenResult = SsoApi.GetProviderToken(providerTokenBag.CorpId, providerTokenBag.CorpSecret);\n                    providerTokenBag.ExpireTime = ApiUtility.GetExpireTime(providerTokenBag.ProviderTokenResult.expires_in);\n                    Update(providerTokenBag, null);//更新到缓存\n                }\n            }\n            return providerTokenBag.ProviderTokenResult;\n        }\n","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Containers/ProviderTokenContainer.cs#L174-L210","documentation":"ProviderTokenContainer.GetTokenResult throws WeixinWorkException with UN_REGISTER_ALERT (\"此CorpId尚未注册，ProviderTokenContainer.Register完成注册（全局执行一次即可）！\") when CheckRegistered(AccessTokenContainer.BuildingKey(corpId, corpSecret)) is false. Provider (通讯录/服务商) tokens require a prior ProviderTokenContainer.Register call that stores the token bag in cache. GetToken delegates to this method, so callers see the same exception.","triggerScenarios":"Calling ProviderTokenContainer.GetToken/GetTokenResult(corpId, corpSecret) without a prior Register(corpId, corpSecret); corpSecret changed so the built key no longer matches the registered one; cache provider emptied.","commonSituations":"New environment deployment where startup registration was omitted; rotating corpSecret invalidates the cache key; in-memory cache reset on app pool recycle with registration only in a one-time script.","solutions":["Call ProviderTokenContainer.Register(corpId, corpSecret) once at application startup before any GetToken call.","Ensure the corpId/corpSecret pair used in GetToken is identical to the one registered.","Re-run registration after cache restarts; prefer registering in app startup code, not one-off scripts.","Wrap first access in a CheckRegistered check that registers on demand for multi-tenant apps."],"exampleFix":"// before\nvar token = ProviderTokenContainer.GetToken(corpId, corpSecret); // throws: not registered\n// after\nif (!ProviderTokenContainer.CheckRegistered(corpId, corpSecret))\n{\n    ProviderTokenContainer.Register(corpId, corpSecret);\n}\nvar token = ProviderTokenContainer.GetToken(corpId, corpSecret);","handlingStrategy":"validation","validationCode":"if (!ProviderTokenContainer.CheckRegistered(corpId, corpSecret))\n{\n    ProviderTokenContainer.Register(corpId, corpSecret);\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    var token = ProviderTokenContainer.GetToken(corpId, corpSecret);\n}\ncatch (WeixinWorkException ex) when (ex.Message.Contains(\"尚未注册\"))\n{\n    log.LogError(ex, \"Provider token for {CorpId} not registered; registering at first use.\", corpId);\n    ProviderTokenContainer.Register(corpId, corpSecret);\n}","preventionTips":["Register provider credentials in application startup, not in manual/one-time setup steps.","After rotating corpSecret, re-register so the cache key matches.","Monitor the WeixinTrace logs for UN_REGISTER_ALERT to catch missed registrations early."],"tags":["provider-token","not-registered","startup-config"],"backgroundTag":"missing-configuration","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"}