BlazorPanzoom icon indicating copy to clipboard operation
BlazorPanzoom copied to clipboard

Exception thrown in Blazor Server .NET 8 when directly accessing a page containing <Panzoom>

Open fterrani opened this issue 1 year ago • 4 comments

Greetings,

I would like to use BlazorPanzoom in a Blazor Server .NET 8 project. The library seem to work properly most of the time, however I think I found a case where it doesn't.

When accessing directly a page that contains a <Panzoom> component, a NullReferenceException is thrown from the Panzoom.cs file:

public async ValueTask DisposeAsync()
{
	GC.SuppressFinalize(this);
	await _underlyingPanzoomInterop.DisposeAsync(); // <<< the line throwing the exception
}

For some reason, the _underlyingPanzoomInterop variable seems to be null... which means the component is, for some reason, disposed before it is even rendered at all? If so, I have no idea why. Maybe the fix is as simple as this?

	await _underlyingPanzoomInterop?.DisposeAsync(); 

But I don't know for certain and might be unaware of some indirect implications that you probably know about. You will find a very basic Blazor Server .NET 8 project (with global rendering config) in attachment of this issue that highlights the problem: BlazorPanzoomDotNet8.zip

Also, here are some useful links related to exception handling when disposing in .NET:

  • https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1065#dispose-methods
  • https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-disposeasync

fterrani avatar Jan 16 '24 15:01 fterrani

I have this issue as well, and it is blocking me from upgrading to .NET 8. Due to the unusual nature of the application I am using it for, I have spent a great deal of time sleuthing around inside of BlazorPanzoom (as well as the original panzoom), so I am going to take a look at it and see if I can't find the source of the issue. If I do, I'll submit a pull request with the fix.

MaxDeVos avatar Jan 27 '24 07:01 MaxDeVos

Fortunately, the general cause of this problem is very clear: .NET 8's rendering modes. We know this because this behavior doesn't occur in WebAssembly environments, such as the included repository's included demos.

I created two absolutely minimal projects from a stripped down BlazorWebApp template, and set up one to render via InteractiveServer and the other to render via client-side WASM, and the issue only occurred in the server-rendered app. Here's the code from Home.razor in the InteractiveServer project which triggered the issue:

@page "/"
<PageTitle>Home</PageTitle>
@rendermode InteractiveServer

<div class="panzoom-parent">
    <Panzoom @ref="_panzoom">
        <div @ref="@context.ElementReference" class="panzoom">
            <img style="width: 400px; height: 400px" src="awesome_tiger.svg" alt="image"/>
        </div>
    </Panzoom>
</div>


@code 
{
    private Panzoom? _panzoom;
    
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (_panzoom != null)
        {
            await _panzoom.ZoomAsync(1);
        }
    }
}

Specifically, the _underlyingPanzoomInterop object in Components/Panzoom.cs is null, and throws an exception here:

public async ValueTask DisposeAsync()
{
    GC.SuppressFinalize(this);
    if (_underlyingPanzoomInterop != null)
    {
        await _underlyingPanzoomInterop.DisposeAsync();
    }
}

MaxDeVos avatar Jan 27 '24 08:01 MaxDeVos

I think this related to issue #12 and unrelated to dotnet 8. The bug has been patched, unfortunately a new package has not been released.

Edit: It was able to easily clone the source from GH, build the project, and reference BlazorPanZoom from my blazor project (without the nuget reference). It works without throwing the error!

PmE8HW0KRfqa avatar Feb 10 '24 07:02 PmE8HW0KRfqa

I think I'm experiencing the same issue. @shaigem could you push a fixed release please?

konst-sh avatar Aug 21 '24 07:08 konst-sh