{"record":{"id":"d682ae9d4989333c","repo":"JeffreySu/WeiXinMPSDK","slug":"containerbag-key","errorCode":null,"errorMessage":"ContainerBag 更新时，Key 不能为空！类型：","messagePattern":"ContainerBag 更新时，Key 不能为空！类型：","errorType":"validation","errorClass":"WeixinException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin/Senparc.Weixin/Containers/BaseContainer.cs","lineNumber":476,"sourceCode":"                //var c2 = ItemCollection.GetCount();\n            }\n            //var containerCacheKey = GetContainerCacheKey();\n\n            bag.CacheTime = SystemTime.Now;\n\n            Cache.Update(cacheKey, bag, expiry);//更新到缓存，TODO：有的缓存框架可一直更新Hash中的某个键值对\n        }\n\n        /// <summary>\n        /// 更新已经添加过的数据项\n        /// </summary>\n        /// <param name=\"bag\">为null时删除该项</param>\n        /// <param name=\"expiry\"></param>\n        public static void Update(TBag bag, TimeSpan? expiry)\n        {\n            if (string.IsNullOrEmpty(bag.Key))\n            {\n                throw new WeixinException(\"ContainerBag 更新时，Key 不能为空！类型：\" + bag.GetType());\n            }\n\n            Update(bag.Key, bag, expiry);\n        }\n\n        /// <summary>\n        /// 更新数据项（本地缓存不会改变原有值的 HashCode）\n        /// </summary>\n        /// <param name=\"shortKey\"></param>\n        /// <param name=\"partialUpdate\">为null时删除该项</param>\n        /// <param name=\"expiry\"></param>\n        public static void Update(string shortKey, Action<TBag> partialUpdate, TimeSpan? expiry)\n        {\n            var cacheKey = GetBagCacheKey(shortKey);\n            if (partialUpdate == null)\n            {\n                Cache.RemoveFromCache(cacheKey);//移除对象\n            }","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin/Senparc.Weixin/Containers/BaseContainer.cs#L458-L494","documentation":"BaseContainer.Update(TBag bag, TimeSpan? expiry) requires the bag's Key to be non-empty, because it delegates to Update(bag.Key, bag, expiry). A bag with a null/empty Key cannot be located in the container, so a WeixinException is thrown to surface the misconfigured bag and its type.","triggerScenarios":"Constructing a new TBag and calling Update without ever assigning bag.Key (or without registering the bag so Key gets set); a bag whose Key assignment was skipped due to a failed property initializer; passing a deserialized bag where Key wasn't populated.","commonSituations":"Manually creating container bags (e.g. new AccessTokenBag/JsApiTicketBag) and pushing them via Update instead of going through Register; custom TBag subclasses overriding Key improperly; JSON deserialization dropping the Key field.","solutions":["Ensure bag.Key is assigned before calling Update (for appid-based bags this is usually the AppId, set via Register).","Use the container's Register method to create/register bags instead of hand-constructing and Updating them.","If the bag is new, give it a unique Key yourself before Update.","Check TBag subclasses/custom bags for Key initialization bugs and add a null-check/constructor requirement for Key."],"exampleFix":"// before\nvar bag = new AccessTokenBag();\nBaseContainer<AccessTokenBag>.Update(bag, null); // Key is null -> throws\n// after\nAccessTokenContainer.Register(appId, appSecret); // recommended: creates a keyed bag\n// or, if manual:\nvar bag = new AccessTokenBag { Key = appId, AppId = appId };\nBaseContainer<AccessTokenBag>.Update(bag, null);","handlingStrategy":"validation","validationCode":"if (string.IsNullOrEmpty(bag.Key))\n    throw new InvalidOperationException($\"{bag.GetType().Name}.Key must be set before Update.\");\nBaseContainer<TBag>.Update(bag, expiry);","typeGuard":"bool IsUpdatable<TBag>(TBag bag) where TBag : IBaseContainerBag =>\n    bag != null && !string.IsNullOrEmpty(bag.Key);","tryCatchPattern":"try\n{\n    BaseContainer<TBag>.Update(bag, expiry);\n}\ncatch (WeixinException ex)\n{\n    Log($\"Bag without Key: {ex.Message}\");\n    // register properly or assign Key, then retry\n}","preventionTips":["Prefer container Register methods over hand-built bags + Update.","Always set Key (usually the AppId) when constructing bags manually.","Check deserialization mappings include the Key field.","Guard Update calls with a Key null/empty check in a shared helper."],"tags":["container","empty-key","state","senparc-weixin"],"backgroundTag":"empty-required-field","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"}