{"record":{"id":"50fadad5db4c975f","repo":"JeffreySu/WeiXinMPSDK","slug":"appid","errorCode":null,"errorMessage":"AppId 不能为空。","messagePattern":"AppId 不能为空。","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.MP/Senparc.Weixin.MP/CommonAPIs/MpApiClient.cs","lineNumber":33,"sourceCode":"using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Senparc.Weixin.CommonAPIs.ApiHandlerWapper;\nusing Senparc.Weixin.Entities;\nusing Senparc.Weixin.MP.Containers;\n\nnamespace Senparc.Weixin.MP\n{\n    /// <summary>\n    /// 公众号实例 API 客户端。适合由业务 DI 容器按账号创建，避免修改静态 Service Locator 委托。\n    /// </summary>\n    public sealed class MpApiClient\n    {\n        public MpApiClient(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.MP,\n                () => AppId,\n                AccessTokenContainer.CheckRegistered,\n                AccessTokenContainer.GetAccessTokenResult,\n                ApiHandlerWapper.InvalidCredentialValues,","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.MP/Senparc.Weixin.MP/CommonAPIs/MpApiClient.cs#L15-L51","documentation":"MpApiClient's constructor validates that the appId argument is a non-empty, non-whitespace string and throws ArgumentException('AppId 不能为空。') otherwise. The library treats a missing AppId as unrecoverable developer error, so it fails fast at construction time rather than when the first API call executes.","triggerScenarios":"Calling `new MpApiClient(appId)` with null, an empty string (\"\"), or a string of only whitespace characters (e.g. from an unset config value).","commonSituations":"AppId read from appsettings.json/environment variables that was never set; DI wiring that passes an unresolved config property; trimming/normalization code that accidentally emptied the value; refactor where the appId field was renamed and the source value lost.","solutions":["Pass the actual WeChat MP AppId string to the MpApiClient constructor.","Check where the appId value originates (config file, env var, database) and confirm it is populated before constructing the client.","If the value comes from configuration, add a startup validation that fails fast with a clear message when the AppId setting is missing or blank.","Trim user-supplied/config values only after verifying they are non-whitespace, never before checking emptiness."],"exampleFix":"// before\nvar client = new MpApiClient(configuration[\"Weixin:AppId\"]); // config missing -> ArgumentException\n// after\nvar appId = configuration[\"Weixin:AppId\"];\nif (string.IsNullOrWhiteSpace(appId))\n    throw new InvalidOperationException(\"Weixin:AppId is not configured.\");\nvar client = new MpApiClient(appId);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrWhiteSpace(appId))\n    throw new ArgumentException(\"AppId must be provided before creating MpApiClient.\", nameof(appId));\nvar client = new MpApiClient(appId);","typeGuard":"bool IsValidAppId(string appId) => !string.IsNullOrWhiteSpace(appId);","tryCatchPattern":"try\n{\n    var client = new MpApiClient(appId);\n}\ncatch (ArgumentException ex) when (ex.ParamName == nameof(appId))\n{\n    _logger.LogError(ex, \"WeChat MP AppId is missing or empty; check configuration.\");\n    throw new ApplicationException(\"MP client misconfigured: empty AppId.\", ex);\n}","preventionTips":["Validate all WeChat configuration keys at startup with fail-fast checks.","Bind config into a typed options class with [Required] attributes and validate via IOptions validation.","Never pass config lookups directly into constructors; read into a variable and check first.","Add unit tests asserting the client throws on empty appId and that your config loader rejects blanks."],"tags":["csharp","argument-validation","configuration","weixin"],"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"}