{"record":{"id":"b206a4da6fa957f9","repo":"JeffreySu/WeiXinMPSDK","slug":"objectdisposedexception-msgauditfinanceclient","errorCode":null,"errorMessage":"ObjectDisposedException (MsgAuditFinanceClient)","messagePattern":"ObjectDisposedException \\(MsgAuditFinanceClient\\)","errorType":"exception","errorClass":"ObjectDisposedException","httpStatus":null,"severity":"error","filePath":"src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/MsgAudit/MsgAuditFinanceClient.cs","lineNumber":317,"sourceCode":"            if (handle == IntPtr.Zero)\n            {\n                throw new InvalidOperationException($\"Finance SDK 的 {operation} 操作返回了空指针。\");\n            }\n        }\n\n        private static void ThrowIfNativeError(int errorCode, string operation)\n        {\n            if (errorCode != 0)\n            {\n                throw new MsgAuditFinanceException(errorCode, operation);\n            }\n        }\n\n        private void ThrowIfDisposed()\n        {\n            if (_disposed)\n            {\n                throw new ObjectDisposedException(nameof(MsgAuditFinanceClient));\n            }\n        }\n\n        private void ReleaseResources(bool disposing)\n        {\n            if (_disposed)\n            {\n                return;\n            }\n\n            _disposed = true;\n            var nativeApi = _nativeApi;\n            _nativeApi = null;\n            if (nativeApi == null)\n            {\n                return;\n            }\n","sourceCodeStart":299,"sourceCodeEnd":335,"githubUrl":"https://github.com/JeffreySu/WeiXinMPSDK/blob/be573f6f94bdbf718dd5f6cdecb137fbc7ff651e/src/Senparc.Weixin.Work/Senparc.Weixin.Work/AdvancedAPIs/MsgAudit/MsgAuditFinanceClient.cs#L299-L335","documentation":"MsgAuditFinanceClient wraps a native SDK handle; ThrowIfDisposed throws ObjectDisposedException naming MsgAuditFinanceClient when GetChatData, DecryptData, or GetMediaData is called after Dispose. Native resources cannot be used after the SDK instance is destroyed.","triggerScenarios":"Calling any data API after client.Dispose() — e.g. reusing a client stored in a field after a using block ended, or a long-lived background job holding a disposed client.","commonSituations":"'using var client = ...' scope ending while async continuations still use the client, singleton service disposed by DI container while background threads still reference it, or accidental early Dispose.","solutions":["Keep the client alive for the full duration of its use; move it out of the using scope or use explicit lifecycle management","Register the client in DI as a singleton/scoped service and let the container dispose it","Recreate a new MsgAuditFinanceClient if the previous one was disposed","Guard background tasks against using clients whose lifetime ended"],"exampleFix":"// before\nMsgAuditFinanceClient client;\nusing (client = new MsgAuditFinanceClient(options)) { }\nclient.GetChatData(...); // disposed\n// after\nusing var client = new MsgAuditFinanceClient(options);\nclient.GetChatData(...); // all usage inside lifetime","handlingStrategy":"type-guard","validationCode":"if (_client is null || _clientDisposed) throw new InvalidOperationException(\"client lifetime ended\");","typeGuard":"bool Usable(MsgAuditFinanceClient? c) => c is not null && !c.Disposed; // track disposal in your wrapper if the client lacks a public flag","tryCatchPattern":"try { var data = client.GetChatData(...); }\ncatch (ObjectDisposedException) { client = new MsgAuditFinanceClient(options); /* recreate and retry once */ }","preventionTips":["Scope client usage strictly inside using blocks or a DI-managed lifetime","Avoid storing using-scoped clients in fields or closures that outlive the scope","Let DI containers own disposal for singletons/background services","Recreate clients lazily via a factory instead of caching instances"],"tags":["csharp","disposed","lifetime","weixin-work"],"backgroundTag":"invalid-state-transition","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"}