System.ObjectDisposedException: Cannot access a disposed object in Blazor component

Galvin Nguyen 0 Reputation points
2024-03-09T09:49:42.31+00:00

I am working on a Blazor project. I have a custom component to show loading animation on a button after clicked to do some async works.

<button class="btn @ButtonCssClass" form="@ForForm" type="@Type" disabled="@IsLoading" @onclick="@((args) => OnClick(args))">
    @if (IsLoading)
    {
        <span class="spinner-border spinner-border-sm text-light" aria-hidden="true"></span>
        <span role="status">@LoadingText</span>
    }
    else
    {
        if (!string.IsNullOrEmpty(IconCss))
        {
            <i class="@IconCss me-2"></i> @NormalText
        }
        else
        {
            @NormalText
        }
    }
</button>

@code {
    [Parameter] public string ButtonCssClass { get; set; } = string.Empty;
    [Parameter] public string NormalText { get; set; } = string.Empty;
    [Parameter] public string LoadingText { get; set; } = string.Empty;
    [Parameter] public string ForForm { get; set; } = string.Empty;
    [Parameter] public string Type { get; set; } = "button";
    [Parameter] public string IconCss { get; set; } = string.Empty;
    [Parameter] public bool IsLoading { get; set; }
    [Parameter] public EventCallback<MouseEventArgs> Click { get; set; }

    void OnClick(MouseEventArgs args)
    {
        Click.InvokeAsync(args);
    }
}

However, when I use the component and pass a method into that Click parameter

<LoadingButton IsLoading="_isLoading" Type="submit" IconCss="fa-solid fa-floppy-disk" ForForm="FormProduct" ButtonCssClass="btn-primary rounded-pill me-2" 
    LoadingText="ĐANG LƯU" NormalText="LƯU" Click="InsertOrUpdateAsync" />

private async Task InsertOrUpdateAsync()
{
    _isLoading = true;
    await Task.Delay(10000);
    var result = await Mediator.Send(new GetAllCategoriesQuery());
    _isLoading = false;
}

there are errors that prevent the LoadingButton component from showing the animation and the query did not execute after the await Task.Delay().

 An exception occurred on the circuit host 'Y7SmUQqQgCje3bMp_xV1ZpO3k7QHKhwNcgVLUxhzrQs' while the client is disconnected.
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'IServiceProvider'.
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ThrowHelper.ThrowObjectDisposedException()
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at MediatR.Wrappers.RequestHandlerWrapperImpl`2.Handle(IRequest`1 request, IServiceProvider serviceProvider, CancellationToken cancellationToken)
   at MediatR.Mediator.Send[TResponse](IRequest`1 request, CancellationToken cancellationToken)
   at CompanyPortal.Components.Admin.Pages.Product.EditProductDialog.InsertOrUpdateAsync() in D:\net-projects\CompanyPortal\CompanyPortal\Components\Admin\Pages\Product\EditProductDialog.razor:line 109
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.Forms.EditForm.HandleSubmitAsync()
   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

Please have a look and give me some advises.

Thank you!

Developer technologies | .NET | Blazor
{count} votes

2 answers

Sort by: Most helpful
  1. AgaveJoe 30,126 Reputation points
    2024-03-09T11:59:29.78+00:00

    A common issue we see on these forums is a design that disposes a DbContext while the DbContext is configured with the scoped lifetime. In a Blazor server side application, the scoped lifetime is same lifetime as the circuit. In other words, the lifetime is the entire application . If the design disposes the DbContext then the DbContext is no longer available unless the application is restarted.

    ASP.NET Core Blazor with Entity Framework Core (EF Core)

    Keep in mind, we have no way to verify the actual issue as we cannot see you code. Also, it looks like you are using MediatR which is a 3rd party library. You should consult the MediatR documentation to make sure you are using the right programming pattern for a Blazor application.


  2. Galvin Nguyen 0 Reputation points
    2024-03-11T13:35:57.69+00:00

    OK, so I add here a full explanation of what I am designing.

    I have multiple CRUD pages. When a user click on a button, for example SAVE, I will call API to save it. Meanwhile, I will show the spinner or whatever animation on that SAVE button. Let's call that LoadingButton component.

    <button class="btn @ButtonCssClass" form="@ForForm" type="@Type" disabled="@IsLoading" @onclick="Click">
        @if (IsLoading)
        {
            <span class="spinner-border spinner-border-sm text-light" aria-hidden="true"></span>
            <span role="status">@LoadingText</span>
        }
        else
        {
            if (!string.IsNullOrEmpty(IconCss))
            {
                <i class="@IconCss me-2"></i> @NormalText
            }
            else
            {
                @NormalText
            }
        }
    </button>
    
    @code {
        [Parameter] public string ButtonCssClass { get; set; } = string.Empty;
        [Parameter] public string NormalText { get; set; } = string.Empty;
        [Parameter] public string LoadingText { get; set; } = string.Empty;
        [Parameter] public string ForForm { get; set; } = string.Empty;
        [Parameter] public string Type { get; set; } = "button";
        [Parameter] public string IconCss { get; set; } = string.Empty;
        [Parameter] public EventCallback<MouseEventArgs> Click { get; set; }
    
        private bool IsLoading { get; set; }
    
    	public void StartLoading()
    	{
    	    IsLoading = true;
    	    StateHasChanged();
    	}
    
    	public void StopLoading()
    	{
    	    IsLoading = false;
    	    StateHasChanged();
    	}
    }
    

    So on one of my dialog, for example EditProductDialog, I will use that button

    <LoadingButton @ref="SubmitButton" IsLoading="_isLoading" Type="submit" IconCss="fa-solid fa-floppy-disk" ForForm="FormProduct" ButtonCssClass="btn-primary rounded-pill me-2" LoadingText="SAVING" NormalText="SAVE" />
    
    

    and use it in Submit method

    private async Task Submit() 
    {
         _isLoading = true;     
         await Task.Delay(5000);    
         _isLoading = false;
    }
    
    

    and as the error on the first post, it throws the exception at the Mediator call. If I remove the assignment to the _isLoading, things just work fine.

    Another problem which I don't know why

    [2024-03-11T13:35:21.071Z] Error: System.AggregateException: One or more errors occurred. (TypeError: Cannot read properties of null (reading 'insertBefore'))
     ---> System.InvalidOperationException: TypeError: Cannot read properties of null (reading 'insertBefore')
       at Microsoft.AspNetCore.Components.RenderTree.Renderer.InvokeRenderCompletedCallsAfterUpdateDisplayTask(Task updateDisplayTask, Int32[] updatedComponents)
       --- End of inner exception stack trace ---
    
    

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.