RadzenDataGridColumn dynamically loads System.Linq.Dynamic.Core for non-simple types which might cause a performance issue #938

Closed
opened 2026-01-29 17:46:36 +00:00 by claunia · 1 comment
Owner

Originally created by @jnsn on GitHub (Jul 25, 2023).

This is not really a bug, but more of a be aware situation. I thought it best to write this down here, as most people who might bump into it might come here first.

I've only validated this against the RadzenDataGridColumn control, as this is the one were I bumped into it, but my guess is other components who use System.Linq.Dynamic.Core behind the scenes might be affected too.

Context

I am using Radzen in a project that has the capability of loading plugins at runtime. To support this we hook into the AssemblyResolve event of the AppDomain.CurrentDomain. Here we have some logic to determine the path and the assemblies of our plugins which need to be loaded. We are aware that we have some performance issues here, and some load operations are quite slow. However, we typically only need to resolve 1 or 2 assemblies so at startup our overhead is quite slow and we enter the event only for each assembly we need to load. At the moment this hasn't been a performance optimization priority for us.

Describe the bug

When a DateTime property is used in a RadzenDataGridColumn, an attempt is made to resolve the System.Linq.Dynamic.Core assembly multiple times. My guess is that this would actually apply to each type that is not considered a simple type, but I haven't verified that.

In our case this means that our AssemblyResolve event handler is called every time and executing our custom, slow, logic, resulting in a very slow display of the grid on a page.

To Reproduce

Program.cs

AppDomain.CurrentDomain.AssemblyResolve += (_, eventArgs) =>
{
    Console.WriteLine("Loading: " + eventArgs.RequestingAssembly?.FullName);
    return null;
};

User.cs

public record User(DateTime Timestamp, string Name, int Age);

TestGrid.razor

@page "/TestGrid"

<RadzenStack>
    <RadzenRow>
        <RadzenColumn Size="12">
            <RadzenDataGrid
                TItem="User"
                Data="@_data"
                AllowSorting="true"
                AllowFiltering="true">
                <Columns>
                    <RadzenDataGridColumn TItem="User" Property="@nameof(User.Timestamp)" Title="Time" FormatString="{0:yyyy-MM-dd HH:mm:ss}" SortOrder="SortOrder.Descending"/>
                    <RadzenDataGridColumn TItem="User" Property="@nameof(User.Name)" Title="Name"/>
                    <RadzenDataGridColumn TItem="User" Property="@nameof(User.Age)" Title="Age" FormatString="{0} years"/>
                </Columns>
            </RadzenDataGrid>
        </RadzenColumn>
    </RadzenRow>
</RadzenStack>

@code {
    private IEnumerable<User> _data = null!;

    protected override void OnInitialized()
    {
        base.OnInitialized();

        _data = new List<User>
        {
            new(DateTime.Now.AddMinutes(-1), "Lando", 23),
            new(DateTime.Now.AddMinutes(-2), "Lewis", 38),
            new(DateTime.Now.AddMinutes(-3), "Max", 25),
            new(DateTime.Now.AddMinutes(-4), "Charles", 25)
        };
    }

}

This produces the following log output:

Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832
Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832
Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832
Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832
Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832
Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832
Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832
Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832

The working workaround is to explicitly set the Type and FilterProperty parameters, and use a template to render the value:

<RadzenDataGridColumn TItem="User" Title="Time" SortOrder="SortOrder.Descending" Type="@typeof(DateTime)" FilterProperty="@nameof(User.Timestamp)">
	<Template Context="item">
		@item.Timestamp.ToString("yyyy-MM-dd HH:mm:ss")
	</Template>
</RadzenDataGridColumn>
Originally created by @jnsn on GitHub (Jul 25, 2023). <!-- IMPORTANT: Read this first!!! 1. If you own a Radzen Professional or Еnterprise subscription you can report your issue or ask us a question via email at info@radzen.com. Radzen staff will reply within 24 hours (Professional) or 16 hours (Enterprise) 2. The Radzen staff guarantees a response to issues in this repo only to paid subscribers. 3. If you have a HOW TO question start a new forum thread in the Radzen Community forum: https://forum.radzen.com. Radzen staff will close issues that are HOWTO questions. 4. Please adhere to the issue template. Specify all the steps required to reproduce the issue or link a project which reproduces it easily (without requiring extra steps such as restoring a database). --> This is not really a bug, but more of a _be aware_ situation. I thought it best to write this down here, as most people who might bump into it might come here first. I've only validated this against the `RadzenDataGridColumn` control, as this is the one were I bumped into it, but my guess is other components who use `System.Linq.Dynamic.Core` behind the scenes might be affected too. **Context** I am using Radzen in a project that has the capability of loading plugins at runtime. To support this we hook into the `AssemblyResolve` event of the `AppDomain.CurrentDomain`. Here we have some logic to determine the path and the assemblies of our plugins which need to be loaded. We are aware that we have some performance issues here, and some load operations are quite slow. However, we typically only need to resolve 1 or 2 assemblies so at startup our overhead is quite slow and we enter the event only for each assembly we need to load. At the moment this hasn't been a performance optimization priority for us. **Describe the bug** When a `DateTime` property is used in a `RadzenDataGridColumn`, an attempt is made to resolve the `System.Linq.Dynamic.Core` assembly multiple times. My guess is that this would actually apply to each type that is not considered a simple type, but I haven't verified that. In our case this means that our `AssemblyResolve` event handler is called every time and executing our custom, slow, logic, resulting in a very slow display of the grid on a page. **To Reproduce** Program.cs ```csharp AppDomain.CurrentDomain.AssemblyResolve += (_, eventArgs) => { Console.WriteLine("Loading: " + eventArgs.RequestingAssembly?.FullName); return null; }; ``` User.cs ```csharp public record User(DateTime Timestamp, string Name, int Age); ``` TestGrid.razor ```csharp @page "/TestGrid" <RadzenStack> <RadzenRow> <RadzenColumn Size="12"> <RadzenDataGrid TItem="User" Data="@_data" AllowSorting="true" AllowFiltering="true"> <Columns> <RadzenDataGridColumn TItem="User" Property="@nameof(User.Timestamp)" Title="Time" FormatString="{0:yyyy-MM-dd HH:mm:ss}" SortOrder="SortOrder.Descending"/> <RadzenDataGridColumn TItem="User" Property="@nameof(User.Name)" Title="Name"/> <RadzenDataGridColumn TItem="User" Property="@nameof(User.Age)" Title="Age" FormatString="{0} years"/> </Columns> </RadzenDataGrid> </RadzenColumn> </RadzenRow> </RadzenStack> @code { private IEnumerable<User> _data = null!; protected override void OnInitialized() { base.OnInitialized(); _data = new List<User> { new(DateTime.Now.AddMinutes(-1), "Lando", 23), new(DateTime.Now.AddMinutes(-2), "Lewis", 38), new(DateTime.Now.AddMinutes(-3), "Max", 25), new(DateTime.Now.AddMinutes(-4), "Charles", 25) }; } } ``` This produces the following log output: ``` Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832 Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832 Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832 Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832 Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832 Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832 Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832 Loading: System.Linq.Dynamic.Core, Version=1.3.0.0, Culture=neutral, PublicKeyToken=0f07ec44de6ac832 ``` The working workaround is to explicitly set the `Type` and `FilterProperty` parameters, and use a template to render the value: ```csharp <RadzenDataGridColumn TItem="User" Title="Time" SortOrder="SortOrder.Descending" Type="@typeof(DateTime)" FilterProperty="@nameof(User.Timestamp)"> <Template Context="item"> @item.Timestamp.ToString("yyyy-MM-dd HH:mm:ss") </Template> </RadzenDataGridColumn> ```
Author
Owner

@enchev commented on GitHub (Jul 26, 2023):

Indeed the property value access, sorting, filtering, grouping, paging, etc. is done using Dynamic Linq. When you use templates you are bypassing the property access and that is why Dynamic Linq is not used - otherwise you will get Dynamic Linq expression for every cell that needs to display a value. There is nothing unusual in the property access expressions and I’m afraid that we cannot do anything to improve this - you can check the source code for reference. You might need to add caching for your assembly load logic.

@enchev commented on GitHub (Jul 26, 2023): Indeed the property value access, sorting, filtering, grouping, paging, etc. is done using Dynamic Linq. When you use templates you are bypassing the property access and that is why Dynamic Linq is not used - otherwise you will get Dynamic Linq expression for every cell that needs to display a value. There is nothing unusual in the property access expressions and I’m afraid that we cannot do anything to improve this - you can check the source code for reference. You might need to add caching for your assembly load logic.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/radzen-blazor#938