{"record":{"id":"be1df100a78675f5","repo":"JeffreySu/WeiXinMPSDK","slug":"credentialprovider","errorCode":null,"errorMessage":"credentialProvider","messagePattern":"credentialProvider","errorType":"validation","errorClass":"ArgumentNullException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.Work/Senparc.Weixin.Work/Containers/AccessTokenContainer.cs","lineNumber":394,"sourceCode":"            string registrationKey,\n            string corpId,\n            IWeixinCredentialProvider credentialProvider,\n            string name = null,\n            CancellationToken cancellationToken = default)\n        {\n            if (string.IsNullOrWhiteSpace(registrationKey))\n            {\n                throw new ArgumentException(\"registrationKey 不能为空。\", nameof(registrationKey));\n            }\n\n            if (string.IsNullOrWhiteSpace(corpId))\n            {\n                throw new ArgumentException(\"CorpId 不能为空。\", nameof(corpId));\n            }\n\n            if (credentialProvider == null)\n            {\n                throw new ArgumentNullException(nameof(credentialProvider));\n            }\n\n            async Task<AccessTokenBag> RegisterCoreAsync(CancellationToken token)\n            {\n                var secret = await credentialProvider.GetSecretAsync(registrationKey, token).ConfigureAwait(false);\n                if (string.IsNullOrWhiteSpace(secret))\n                {\n                    throw new InvalidOperationException(\"凭据提供器返回了空 CorpSecret。\");\n                }\n\n                var bag = new AccessTokenBag\n                {\n                    Name = name,\n                    CorpId = corpId,\n                    CorpSecret = secret,\n                    ExpireTime = DateTimeOffset.MinValue,\n                    AccessTokenResult = new AccessTokenResult()\n                };","sourceCodeStart":376,"sourceCodeEnd":412,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.Work/Senparc.Weixin.Work/Containers/AccessTokenContainer.cs#L376-L412","documentation":"AccessTokenContainer.RegisterWithCredentialProviderAsync throws ArgumentNullException with parameter name \"credentialProvider\" when the IWeixinCredentialProvider instance is null. The provider is required because it supplies the corp secret via GetSecretAsync; registering without it cannot produce a token bag. The check happens after the string validations and before RegisterCoreAsync runs.","triggerScenarios":"Calling RegisterWithCredentialProviderAsync(regKey, corpId, null) — e.g. DI failed to resolve IWeixinCredentialProvider, or a manual construction passed null.","commonSituations":"Missing DI registration for the credential provider implementation so the injected parameter is null; conditional wiring in tests that skipped the provider; property not initialized before use.","solutions":["Pass an actual IWeixinCredentialProvider implementation (custom or library-supplied) to the call.","Register your provider in the DI container (services.AddSingleton<IWeixinCredentialProvider, MyProvider>()) and inject it instead of newing up.","If resolved dynamically, assert non-null with a clear startup error before calling Register."],"exampleFix":"// before\nawait AccessTokenContainer.RegisterWithCredentialProviderAsync(regKey, corpId, provider); // provider null (DI miss)\n// after\nservices.AddSingleton<IWeixinCredentialProvider, ConfigCredentialProvider>();\nvar provider = serviceProvider.GetRequiredService<IWeixinCredentialProvider>();\nawait AccessTokenContainer.RegisterWithCredentialProviderAsync(regKey, corpId, provider);","handlingStrategy":"validation","validationCode":"if (provider is null)\n    throw new InvalidOperationException(\"IWeixinCredentialProvider not registered in DI.\");\nawait AccessTokenContainer.RegisterWithCredentialProviderAsync(regKey, corpId, provider);","typeGuard":"bool HasProvider(IWeixinCredentialProvider? p) => p is not null;","tryCatchPattern":"try\n{\n    await AccessTokenContainer.RegisterWithCredentialProviderAsync(regKey, corpId, provider);\n}\ncatch (ArgumentNullException ex) when (ex.ParamName == \"credentialProvider\")\n{\n    log.LogCritical(\"Credential provider is null; check DI registrations.\");\n    throw;\n}","preventionTips":["Always resolve the provider via DI GetRequiredService so a missing registration fails with a clear message.","Add an integration test that boots the app and performs token registration once.","Avoid optional provider properties that default to null."],"tags":["argument-null","credential-provider","dependency-injection"],"backgroundTag":"null-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"}