{"record":{"id":"ee5cc9aff29e31b0","repo":"JeffreySu/WeiXinMPSDK","slug":"appid-accesstokencontainer","errorCode":null,"errorMessage":"AppId 不能为空。","messagePattern":"AppId 不能为空。","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.MP/Senparc.Weixin.MP/Containers/AccessTokenContainer.cs","lineNumber":287,"sourceCode":"            //为JsApiTicketContainer进行自动注册\n            var registerJsApiTask = JsApiTicketContainer.RegisterAsync(appId, appSecret, name);\n\n            await Task.WhenAll(new[] { registerTask, registerJsApiTask }).ConfigureAwait(false);//等待所有任务完成\n        }\n\n        /// <summary>\n        /// 使用外部凭据提供器注册 AccessToken。自动重注册委托只捕获提供器，不长期捕获明文 AppSecret。\n        /// 此入口仅注册 AccessToken；如需 JS-SDK Ticket，请为对应容器单独配置凭据提供器。\n        /// </summary>\n        public static async Task RegisterWithCredentialProviderAsync(\n            string appId,\n            IWeixinCredentialProvider credentialProvider,\n            string name = null,\n            CancellationToken cancellationToken = default)\n        {\n            if (string.IsNullOrWhiteSpace(appId))\n            {\n                throw new ArgumentException(\"AppId 不能为空。\", nameof(appId));\n            }\n\n            if (credentialProvider == null)\n            {\n                throw new ArgumentNullException(nameof(credentialProvider));\n            }\n\n            SetRegistrationCallback(appId, async () =>\n            {\n                var secret = await credentialProvider.GetSecretAsync(appId, CancellationToken.None).ConfigureAwait(false);\n                if (string.IsNullOrWhiteSpace(secret))\n                {\n                    throw new InvalidOperationException(\"凭据提供器返回了空 AppSecret。\");\n                }\n\n                var bag = new AccessTokenBag\n                {\n                    Name = name,","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.MP/Senparc.Weixin.MP/Containers/AccessTokenContainer.cs#L269-L305","documentation":"RegisterWithCredentialProviderAsync validates its inputs up front and throws ArgumentException('AppId 不能为空。') when the appId parameter is null, empty, or whitespace. Registration cannot proceed without an identity to key the cache and callbacks on.","triggerScenarios":"Calling AccessTokenContainer.RegisterWithCredentialProviderAsync(null/'', credentialProvider) — e.g. an appId sourced from an unset configuration entry, a failed tenant lookup, or a variable defaulted to empty.","commonSituations":"Multi-tenant setups where a tenant's appId column is empty in the database; config binding that silently yields empty strings; code paths that pass an uninitialized variable straight into registration.","solutions":["Supply a valid non-empty appId to RegisterWithCredentialProviderAsync.","Validate/trim the appId at the call site before invoking registration.","Fix the upstream data source (config key, DB row) that produced the empty value.","Add a startup sanity check that enumerates tenants/appIds and fails early if any is blank."],"exampleFix":"// before\nawait AccessTokenContainer.RegisterWithCredentialProviderAsync(tenant.AppId, provider); // AppId may be empty\n// after\nif (string.IsNullOrWhiteSpace(tenant.AppId))\n    throw new InvalidOperationException($\"Tenant {tenant.Id} has no AppId configured.\");\nawait AccessTokenContainer.RegisterWithCredentialProviderAsync(tenant.AppId, provider);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(appId))\n    throw new InvalidOperationException(\"Cannot register credential provider: appId is null or empty.\");\nawait AccessTokenContainer.RegisterWithCredentialProviderAsync(appId, provider);","typeGuard":"bool CanRegister(string appId) => !string.IsNullOrWhiteSpace(appId);","tryCatchPattern":"try\n{\n    await AccessTokenContainer.RegisterWithCredentialProviderAsync(appId, provider);\n}\ncatch (ArgumentException ex) when (ex.ParamName == nameof(appId))\n{\n    _logger.LogError(ex, \"Registration rejected: appId for tenant {TenantId} is empty.\", tenant.Id);\n    throw;\n}","preventionTips":["Validate tenant records (non-empty AppId) before iterating registrations at startup.","Validate DB/config-sourced appIds as soon as they are loaded.","Log which tenants were skipped/rejected during bulk registration.","Fail application startup if any mandatory tenant appId is blank."],"tags":["csharp","argument-validation","weixin","configuration"],"backgroundTag":"missing-required-argument","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"}