Skip to content

[Bug]: Cannot access a disposed object #4023

@AnhNguyenDaenet

Description

@AnhNguyenDaenet

Describe the bug 🐞

When we call a js script in our C# project:

var user = await _jsRuntime.InvokeAsync<User>("signIn", _config.AzureAd.ClientId, _config.AzureAd.Authority);

A pop up will appear and we will log in with our account.

This is how the script looks like

async function signIn(clientId, authority) {
    let loginRequest = {
        prompt: 'select_account',
        scopes: ["User.Read"],
        state: btoa(Date.now()),
        sid: btoa(Date.now())
    };

    let msalConfig = {
        auth: {
            clientId: clientId,
            authority: authority,
            redirectUri: "/",
            navigateToLoginRequestUrl: true,
        },
        cache: {
            storeAuthStateInCookie: false,
            cacheLocation: "memoryStorage",
            temporaryCacheLocation: "memoryStorage"
        },
    };
    let userIdentifier = null;
    let userEmail = null;
    MSALObj = new msal.PublicClientApplication(msalConfig);
    await MSALObj.initialize();

    try {
        const authResponse = await MSALObj.loginPopup(loginRequest);
        const logoutHint = authResponse.account.idTokenClaims.login_hint;
        if (logoutHint == null) {
            console.log("No logout hint found to logout user automatically again");
        }
        userIdentifier = authResponse.account.idTokenClaims.oid;
        userEmail = authResponse.account.idTokenClaims.preferred_username;
        const handle = await MSALObj.logoutPopup({ logoutHint: logoutHint });

        console.log("returning user with id: " + authResponse?.account?.idTokenClaims?.oid + " and email: " + authResponse.account.idTokenClaims.preferred_username);
        return { UserIdentifier: authResponse.account.idTokenClaims.oid, UserEmail: authResponse.account.idTokenClaims.preferred_username };
    } catch (error) { }

    if (userIdentifier != null || userEmail != null) {
        return { UserIdentifier: userIdentifier, UserEmail: userEmail };
    }
    return null;
}

Everything is fine until this line is called:

const handle = await MSALObj.logoutPopup({ logoutHint: logoutHint });

And we got the following exception:

 ---> (Inner Exception #3) System.ObjectDisposedException: Cannot access a disposed object.
   at System.Reactive.Subjects.Subject`1.ThrowDisposed()
   at System.Reactive.Subjects.Subject`1.OnNext(T value)
   at ReactiveUI.ViewModelActivator.Deactivate(Boolean ignoreRefCount) in /_/src/ReactiveUI/Activation/ViewModelActivator.cs:line 96
   at ReactiveUI.ViewModelActivator.<Activate>b__10_0() in /_/src/ReactiveUI/Activation/ViewModelActivator.cs:line 80
   at System.Reactive.Disposables.AnonymousDisposable.Dispose()
   at System.Reactive.Disposables.Disposable.TrySetSerial(IDisposable& fieldRef, IDisposable value)
   at System.Reactive.Disposables.SerialDisposableValue.set_Disposable(IDisposable value)
   at System.Reactive.Disposables.SerialDisposable.set_Disposable(IDisposable value)
   at ReactiveUI.ViewForMixins.<>c__DisplayClass11_0.<HandleViewModelActivation>b__0(Boolean activated) in /_/src/ReactiveUI/Activation/ViewForMixins.cs:line 259
   at System.Reactive.AnonymousSafeObserver`1.OnNext(T value)
   at System.Reactive.Sink`1.ForwardOnNext(TTarget value)
   at System.Reactive.Linq.ObservableImpl.Merge`1.Observables._.InnerObserver.OnNext(TSource value)
   at System.Reactive.Sink`1.ForwardOnNext(TTarget value)
   at System.Reactive.Linq.ObservableImpl.Select`2.Selector._.OnNext(TSource value)
   at System.Reactive.Sink`1.ForwardOnNext(TTarget value)
   at System.Reactive.IdentitySink`1.OnNext(T value)
   at System.Reactive.Subjects.Subject`1.OnNext(T value)
   at ReactiveUI.Blazor.ReactiveInjectableComponentBase`1.Dispose(Boolean disposing) in /_/src/ReactiveUI.Blazor/ReactiveInjectableComponentBase.cs:line 135
   at ReactiveUI.Blazor.ReactiveInjectableComponentBase`1.Dispose() in /_/src/ReactiveUI.Blazor/ReactiveInjectableComponentBase.cs:line 65
   at Microsoft.AspNetCore.Components.Rendering.ComponentState.DisposeAsync()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.Dispose(Boolean disposing)<---

We need to click the try button and sign in again to continue our process. This time, 2-factor authentication is not asking anymore.

Should we add a check in ViewModelActivator to not calling dispose method if object is already disposed?

Nuget ver:

"ReactiveUI.Blazor": "20.1.1"

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions