{"record":{"id":"707c98b38ebe70e2","repo":"JeffreySu/WeiXinMPSDK","slug":"appid-wxopenapiclient","errorCode":null,"errorMessage":"AppId 不能为空。","messagePattern":"AppId 不能为空。","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/CommonAPIs/WxOpenApiClient.cs","lineNumber":36,"sourceCode":"using Senparc.Weixin.CommonAPIs.ApiHandlerWapper;\nusing Senparc.Weixin.Entities;\nusing Senparc.Weixin.WxOpen.Containers;\n\nnamespace Senparc.Weixin.WxOpen\n{\n    /// <summary>\n    /// 微信小程序实例 API 客户端。适合由业务 DI 容器按应用创建。\n    /// </summary>\n    public sealed class WxOpenApiClient\n    {\n        private static readonly int[] InvalidCredentialValues =\n            { (int)ReturnCode.获取access_token时AppSecret错误或者access_token无效 };\n\n        public WxOpenApiClient(string appId)\n        {\n            AppId = !string.IsNullOrWhiteSpace(appId)\n                ? appId\n                : throw new ArgumentException(\"AppId 不能为空。\", nameof(appId));\n        }\n\n        public string AppId { get; }\n\n        public T Execute<T>(Func<string, T> operation, bool retryInvalidCredential = true)\n            where T : WxJsonResult, new()\n        {\n            if (operation == null)\n            {\n                throw new ArgumentNullException(nameof(operation));\n            }\n\n            return ApiHandlerWapperBase.TryCommonApiBase(\n                PlatformType.WxOpen,\n                () => AppId,\n                AccessTokenContainer.CheckRegistered,\n                AccessTokenContainer.GetAccessTokenResult,\n                InvalidCredentialValues,","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.WxOpen/src/Senparc.Weixin.WxOpen/Senparc.Weixin.WxOpen/CommonAPIs/WxOpenApiClient.cs#L18-L54","documentation":"The WxOpenApiClient constructor validates that appId is non-empty and throws ArgumentException ('AppId 不能为空。') otherwise. Every request executed through this client depends on a valid AppId, so the library refuses to construct an invalid instance.","triggerScenarios":"new WxOpenApiClient(null), new WxOpenApiClient(\"\"), or a config-bound appId string that is null/whitespace at DI/composition time.","commonSituations":"appsettings section for the Mini Program not populated; environment variable not set in production; DI config binding silently leaving the string null.","solutions":["Pass a valid Mini Program AppId (from the WeChat MP console) to the constructor","Validate configuration at startup (fail fast if the AppId binding is empty)","Check the config key/env var name matches what your loader reads"],"exampleFix":"// before\nvar client = new WxOpenApiClient(config[\"WxOpen:AppId\"]); // may be null\n// after\nvar appId = config[\"WxOpen:AppId\"] ?? throw new InvalidOperationException(\"WxOpen:AppId not configured\");\nvar client = new WxOpenApiClient(appId);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(appId)) throw new InvalidOperationException(\"WxOpen AppId is not configured\");","typeGuard":"bool IsValidAppId(string appId) => !string.IsNullOrWhiteSpace(appId);","tryCatchPattern":"try { var client = new WxOpenApiClient(appId); }\ncatch (ArgumentException ex) { logger.LogCritical(ex, \"AppId missing — check configuration\"); throw; }","preventionTips":["Bind and validate Mini Program settings at startup (IOptions validation)","Keep AppId/Secret in one settings section consumed everywhere","Add a health check that constructs the client at boot"],"tags":["wxopen","appid","constructor-validation","configuration"],"backgroundTag":"invalid-constructor-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"}