dotnet/wpf · error · ObjectDisposedException

SR.CryptoProviderDisposed

Error message

SR.CryptoProviderDisposed

What it means

CryptoProvider.CheckDisposed throws ObjectDisposedException with message SR.CryptoProviderDisposed when any member (Encrypt, Decrypt, BlockSize, CanMergeBlocks, BoundGrants, CanEncrypt, CanDecrypt, etc.) is used after Dispose was called. The provider wraps an unmanaged DRM handle that is released on Dispose, so further calls are invalid.

Solutions

  1. Keep the CryptoProvider alive for the whole usage window; extend the using scope or dispose only after last use
  2. Re-create the provider from the UseLicense and SecureEnvironment when the old one was disposed
  3. Check _disposed via a public wrapper or track disposal in your own flag before calling members
  4. Centralize ownership so exactly one component disposes the provider

Example fix

// before
CryptoProvider provider;
using (var tmp = useLicense.Bind(env)) { provider = tmp; } // disposed here
provider.Encrypt(data); // ObjectDisposedException
// after
using (var provider = useLicense.Bind(env))
{
    var cipher = provider.Encrypt(data); // used inside lifetime
}
Defensive patterns

Strategy: try-catch

Validate before calling

bool usable = provider != null && !isDisposedFlag; // track disposal in a wrapper class

Type guard

bool IsUsable(CryptoProvider p) => p != null && !isDisposedTracker.Contains(p);

Try / catch

try { blockSize = provider.BlockSize; }
catch (ObjectDisposedException)
{ provider = useLicense.Bind(env); blockSize = provider.BlockSize; }

Prevention

When it happens

Trigger: Calling Encrypt/Decrypt/BlockSize/CanMergeBlocks/BoundGrants/CanEncrypt on a CryptoProvider after its Dispose() ran — commonly due to a using block, deterministic finalization, or caching the provider beyond the scope in which it was disposed.

Common situations: Storing the CryptoProvider in a long-lived field while wrapping creation in using; reusing a provider across requests after a request-scoped dispose; double-dispose then late access.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14). Data as JSON: /api/errors/3213c3cbc63d462e. Report an issue: GitHub.

Appendix: source

Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/Security/RightsManagement/CryptoProvider.cs:373

            else
            {
                return new UnsignedPublishLicense(BoundLicenseOwnerViewRightsHandle, serializedPublishLicense);
            }
        }

        //------------------------------------------------------
        //
        //  Private Methods  
        //
        //------------------------------------------------------

        /// <summary>
        /// Call this before accepting any API call 
        /// </summary>
        private void CheckDisposed()
        {
            if (_disposed)
                throw new ObjectDisposedException(null, SR.CryptoProviderDisposed);
        }


        private int QueryBlockSize()
        {
            uint attributeSize = 0;
            byte[] dataBuffer = null;
            
            uint encodingType;

            int hr = SafeNativeMethods.DRMGetInfo(DecryptorHandle,
                                                    NativeConstants.QUERY_BLOCKSIZE,
                                                    out encodingType,
                                                    ref attributeSize,
                                                    null);
            Errors.ThrowOnErrorCode(hr);

            // it must return 4 bytes for block size 

View on GitHub (pinned to 81131a70a4)