Completed
Last Updated: 08 Sep 2020 12:35 by ADMIN
Release 2.17.0
René
Created on: 20 Feb 2020 11:23
Category: Grid
Type: Bug Report
10
ObjectDisposedException when Disposing Grid

1. Load a page with a Grid with Reorderable = true

2. While Grid is rendering load a different page

--> Unhandled ObjectDisposedException


Error: System.ObjectDisposedException: Cannot access a disposed object.

Object name: 'DotNetObjectReference`1'.

   at Microsoft.JSInterop.DotNetObjectReference`1.ThrowIfDisposed()

   at Microsoft.JSInterop.JSRuntime.TrackObjectReference[TValue](DotNetObjectReference`1 dotNetObjectReference)

   at Microsoft.JSInterop.Infrastructure.DotNetObjectReferenceJsonConverter`1.Write(Utf8JsonWriter writer, DotNetObjectReference`1 value, JsonSerializerOptions options)

   at System.Text.Json.JsonSerializer.WriteDictionary[TProperty](JsonConverter`1 converter, JsonSerializerOptions options, WriteStackFrame& current, Utf8JsonWriter writer)

   at System.Text.Json.JsonPropertyInfoNotNullable`4.OnWriteDictionary(WriteStackFrame& current, Utf8JsonWriter writer)

   at System.Text.Json.JsonPropertyInfo.WriteDictionary(WriteStack& state, Utf8JsonWriter writer)

   at System.Text.Json.JsonSerializer.HandleDictionary(JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state)

   at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)

   at System.Text.Json.JsonSerializer.WriteCore(Utf8JsonWriter writer, Object value, Type type, JsonSerializerOptions options)

   at System.Text.Json.JsonSerializer.WriteCore(PooledByteBufferWriter output, Object value, Type type, JsonSerializerOptions options)

   at System.Text.Json.JsonSerializer.WriteCoreString(Object value, Type type, JsonSerializerOptions options)

   at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](String identifier, CancellationToken cancellationToken, Object[] args)

   at Microsoft.JSInterop.JSRuntime.InvokeWithDefaultCancellation[T](String identifier, Object[] args)

   at Telerik.Blazor.Components.Grid.GridHeaderRowBase`1.InitColumnReorderable()

   at Telerik.Blazor.Components.Grid.GridHeaderRowBase`1.OnAfterRenderAsync(Boolean firstRender)

   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)

You might have to try a few times to dispose the page at the correct time.  With larger Grids it happens more frequently.

Grids without Reorderable = true do not throw an exception!

19 comments
ADMIN
Marin Bratanov
Posted on: 14 Aug 2020 13:23

Hi Fabian,

The best way to know when updates happen is to click the Follow button on the page and the portal will send you emails with updates as they occur. We do keep the portal as up-to-date as possible and this page's status will also be updated when we work on a fix for this (the page would then also include the version number that will carry it).

 

Regards,
Marin Bratanov
Progress Telerik

Fabian
Posted on: 14 Aug 2020 07:40

Hey Martin, 

we have the exact same problem with our Grid. It is fixed when we set Reorderable=false. But obviously we would like that feature. Are there any news on the front of this bugfix? 

Thanks and best regards

Fabian

ADMIN
Marin Bratanov
Posted on: 05 May 2020 07:57

Hi Philip,

Reducing the grid size helps and it is the best one I can offer. The next one is what I offered in my previous post - implementing a column chooser where people will set the size and order of the columns they want visible.

I have seen similar exception a couple of times and at this point they look a lot like performance issues in the framework - it simply can't catch up quickly enough between the C# and JS parts of the code. Whether it will be possible for us to somehow work around this will require a significant research, and it is not a given - the error is all in the framework, the stack trace does not indicate a place where we could plug to avoid it somehow.

That said, I have raised the priority of this issue so maybe we could get to investigating it in one of the next releases.

 

Regards,
Marin Bratanov
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
Philip
Posted on: 05 May 2020 06:06
Any work-around for this?
Philip
Posted on: 05 May 2020 06:06
^^ upvote
ADMIN
Marin Bratanov
Posted on: 24 Feb 2020 14:36

I can suggest a couple of things to improve the UX with those constraints:

  • Implement a column chooser: https://feedback.telerik.com/blazor/1450105-column-chooser. This will let them pick ony certain columns and that way there may be more real estate for the current ones. You can now use a MultiSelect widget for that, by the way.
  • Use a descriptor for the columns that also has a field for their Width so you can predefine some common requests. You can also edit those fields through the column chooser grid so your end users can have control over that and then even store the state they chose in a database (see here).

 

 

Regards,
Marin Bratanov
Progress Telerik

 UI for Blazor
René
Posted on: 24 Feb 2020 14:27

Thanks for the insight!

So for now I'll keep reorderable/resizable off until I have persuaded my users that paging is something good :-)

 


ADMIN
Marin Bratanov
Posted on: 24 Feb 2020 14:20

Hi René,

Yes, it will be there in 2.8.0, this is not about our performance but how the framework lags a little behind the UI in and disposal in such scenarios. It is a guess, but maybe the WASM flavor won't have this issue (but it is not production-ready yet). We will need to get to investigating this particular scenario and error to see if we can solve it, it is rather specific.

The virtual scrolling is unlikely to support grouping because grouping is recursive and changes dramatically the rendering, while virtualization features rely on steady rendering of the same items. You can find the other limitations of this feature in its docs: https://docs.telerik.com/blazor-ui/components/grid/virtual-scrolling#limitations. You may also find useful the Notes section above it. FIltering, works fine with virtualization, however, so that may be useful.

 

Regards,
Marin Bratanov
Progress Telerik

 UI for Blazor
René
Posted on: 24 Feb 2020 14:16

Hello Marin,

good to hear you could reproduce the error.  So I guess it will still be there with 2.8.0 ?

I know that with large grids the browser performance suffers but unfortunately paging is not always an option because some of the grids are used to get a quick overview over a lot of data.  Scanning data while scrolling is alright but most my users find paging very annoying.  I would like to switch to virtual scrolling but right now it is not an option either because it does not support Grouping.  Will it support Grouping in the future?

ADMIN
Marin Bratanov
Posted on: 24 Feb 2020 14:08

Hi René,

That's over 3000 DOM elements for the table, and at this size browser performance suffers, and with a second layer of DOM manipulation abstractions (Blazor) on top of it, things can get messy.

My best advice is to reduce the page size. This will help with general performance as well, not just this error.

I can reproduce the error with large grids (I could not with <20 rows by 30 columns), and I am logging this for research so we can see if there is anything we can do to avoid/suppress the error.

Regards,
Marin Bratanov
Progress Telerik

 UI for Blazor
René
Posted on: 24 Feb 2020 13:18

Hello Marin,

we have way more than 10 rows on a page.  If we use paging than we have at least 50 or 100 rows on a page.  For some grids we don't use paging at all.

If you can give it one more try: Create a grid with 30 columns and 100 rows and then try again switching tabs.

ADMIN
Marin Bratanov
Posted on: 24 Feb 2020 13:14

Hello,

I cannot reproduce an error with this and switching tabs (based on the previous grid with the 30 columns and 10 items per page:

<TelerikTabStrip>
    <TabStripTab Title="First">
        <GridWithSlowData />
    </TabStripTab>
    <TabStripTab Title="second">
        <GridWithSlowData />
    </TabStripTab>
</TelerikTabStrip>

The 2.8.0 release should be out by the end of day today (perhaps even within a couple of hours). Let's try this with 2.8.0 and see if it still manifests.

At this point I am thinking that this issue may be related to the missing proper unmounting hook in the framework (see https://github.com/dotnet/aspnetcore/issues/13026). We do use the Dispose method from IDisposable to call the .DisposeDotNetObjectRef(DotNetInstance); method of the JS interop we use, and to also call other JS code to clean up our objects, and it is up to the framework to handle that gracefully (we have it in a  if (DotNetInstance != null) block, so it should not throw). It looks like the framework has managed to dispose something in a wrong place/time, however, and throws, and I am not sure we can control that.

Regards,
Marin Bratanov
Progress Telerik

 UI for Blazor
René
Posted on: 24 Feb 2020 13:01

Hello Marin,

most of the time (and very frequently) it happened when switching to another tab. 

Sometimes it also occured when the grid was refreshed after filtering the data with a custom multi-search (setting GridData from AllData to FilteredData).

Right now I don't have the time to switch reorderable/resizable on again for capturing a video.

If a find the time I might do that later.

I'm glad to hear that 2.8.0 will bring improved grid performance!

ADMIN
Marin Bratanov
Posted on: 24 Feb 2020 12:51

Hello René,

The window during a component initialization is so narrow that I am not sure how such a test can be achieved in general. For example, a WASM app would be "frozen" because all rendering and initialization happens in one thread (WASM in the browser does not do multithreading yet) so the next click should not register, on the server the performance and initialization should be faster. Moreover, with our upcoming 2.8.0 release, the grid performance will improve drastically, which should reduce this window.

In the meantime, I can suggest reducing the HTML footprint of the grid - usually reducing the number of rows helps. The sheer amount of HTML to render and maintain can slow down a browser - for example, 25 columns x 20 rows (without templates, templates will weigh things down more) will result in about 600 DOM elements for the cells and rows alone which does not consider any logic running behind them.

I tried my previous sample and approach by adding 30 columns like this (with and without the artificial Task.Delay() in the data loading):

 

        @foreach (var item in Enumerable.Range(1, 30))
        {
            <GridColumn Field=@nameof(SampleData.LastName) Title="Last Name" />
        }

 

But I did not manage to reproduce an error. How do you reproduce that? Do you click a different tab or a NavLink? You could send me a short video of your actual case in a private ticket (in order to keep any sensitive data on the screen from the general public) so I can see what to do in order to try to reproduce this.

Regards,
Marin Bratanov
Progress Telerik

 UI for Blazor
René
Posted on: 24 Feb 2020 12:15

Hello Marin,

after watching your video I have the following comments:

The error does not occur if page is disposed when loading data but if page is disposed while rendering a grid!

We have the following code structure:

A page contains a tabstrip with multiple tabs.  On the tabs there are grids with a least ten sometimes up to 25  columns (many of them templates) and a lot of rows.

Data is loaded in OnAfterRenderAsync when firstRender is true.  (We don't use OnInitializedAsync because we want to display a loading indicator while loading).

We have a cancellationToken whis is invalidated in the Dispose Method.  We use that token to cancel our async data loading when the user leaves the page while loading.  This works and does not throw exceptions.

The exceptions seem to occur if the page is disposed in the timespan between the finished loading of data and the finished rendering of the grid!

Since I have disabled reordering and resizing of the grids we did not have any more exceptions.

I hope that helps to understand the problem!

Regards,

René

ADMIN
Marin Bratanov
Posted on: 21 Feb 2020 10:22

Hello René,

Thank you for the update.

If you have any guidance on what I might be missing and what I can try to reproduce this, you can write it up in a few sentences for me to test even if you don't have a full repro now.

 

Regards,
Marin Bratanov
Progress Telerik

 UI for Blazor
René
Posted on: 21 Feb 2020 10:12

Hello Marin,

unfortunately those exceptions break the app (it does not react anymore until reloaded).

This happened very frequently in our application.  Yesterday I removed Reorderable and Resizable from all Grids and so far we have not had any more crashes.

I cannot provide you with the code of our app but when I find the time I'll let your more on how it is structured and maybe try to create a sample app with the same problem.

ADMIN
Marin Bratanov
Posted on: 21 Feb 2020 10:07

Hi René,

How do you reproduce this? I tried adding a grid that is very slow to get its data and toggle between views while it is loading, but I don't get any errors. I am attaching here the code and a video from my tests that shows what I tried. My first explanations on "blocking the thread" are too succinct in the video - I meant that when this wait happens during pre-rendering it will have to wait until it can actually do the render. I don't think that's related to this issue, though.

Judging from this, it looks like somehow the component (page) got to the point where JS Interop can be registered (OnAfterRenderAsync for the grid component) and the grid initialized its reordareble/resizable functionality. Why would the framework have disposed its objects at that point is beyond me, and it looks like an issue with the component lifecycle - at this point there is no proper method for disposing things when a component is removed from view, and the Dispose() method is not always suitable because it is not guaranteed when it will fire. You can read more about this here: https://github.com/dotnet/aspnetcore/issues/13026

That said, if I can reproduce this error, we could look into it to see if there might be anything we can do to avoid it (although another one that depends on it here can't be). Does this exception break the app, or does it only show in the logs?

 

Regards,
Marin Bratanov
Progress Telerik

 UI for Blazor
Attached Files:
René
Posted on: 20 Feb 2020 14:03

I just encountered the same problem with a grid without Reorderable = true but with Resizable = true.

The exception stack is the same except for "InitColumnReorderable()" is being replaced by "InitColumnResizable()"