Just released our new major version of Radzen.Blazor 6.0.0 without reference to System.Linq.Dynamic.Core NuGet package

Hey folks,

We just released our new major version of Radzen.Blazor 6.0.0 without reference to System.Linq.Dynamic.Core NuGet package, due to recent turmoil related to this package vulnerability issues. Although the author of the popular Dynamic LINQ library fixed the reported problems we've decided to reimplement everything related in Radzen.Blazor from scratch including:

  • Filtering, sorting, grouping, member access, etc. in components like DataGrid, DataFilter, DropDown, DropDownDataGrid, ListBox, AutoComplete, etc. are reworked with dynamic expression trees.
  • Where() and Select() by strings are reworked using Microsoft Roslyn, methods like ToFilterString() used to collect filtering from DataGrid now will return valid C# strings that can be used by both our and Dynamic LINQ library extension methods. For example:

5.x (no item instance reference (i => i.), and/or instead &&/||, single = instead ==.

CustomerID = "a" and Customer.CompanyName.Contains("a")

6.x

i => i.CustomerID == "a" && i.Customer.CompanyName.Contains("a")

If you need something extra in your app offered by Dynamic LINQ you need to add reference to System.Linq.Dynamic.Core NuGet package:

<PackageReference Include="System.Linq.Dynamic.Core" Version="*">
  <Aliases>DynamicLinqCore</Aliases>
</PackageReference>

Program.cs

extern alias DynamicLinqCore;
global using DynamicLinq = DynamicLinqCore::System.Linq.Dynamic.Core;

Your class:

using DynamicLinq

We did our best to avoid any breaking changes in any functionality across all of our products, still if you spot something you can report it here and use 5.x until we fix the problem.

Happy coding!

3 Likes

While upgrading from 5.x to 6.x I ran into an issue with parameterized queries where boolean properties are used:

new Query() { Filter = $@"i => i.IsActive == @0", FilterParameters = [true], OrderBy = $"SortOrder desc" }

This expression works without problems in version 5 but now with 6.0.0 I get the error:

"System.InvalidOperationException: Invalid Where selector
   at System.Linq.Dynamic.Core.DynamicExtensions.Where[T](IQueryable`1 source, String selector, Object[] parameters, Object[] otherParameters)"

If I do not use the FilterParameters and put the parameter directly into the filter it works also with 6.0.0:

new Query() { Filter = $@"i => i.IsActive == true", FilterParameters = [], OrderBy = $"SortOrder desc" }

Also, in older pages initially generated with Radzen Studio, I have queries where the OrderBy parameter contains an item reference:

new Query() { Filter = $@"i => i.CustomerAccountId == @0", FilterParameters = [CustomerAccount.Id], OrderBy = $"x => x.DateProcessed ?? x.DateCreated desc" }

This also does not work any more, telling that x is not a property of my table class.

Thanks for the report @JustJoe! We will provide fix later today, in the meantime you can use 5.x versions instead.

I think there is still issue some with v.6.0.3 (v5.9.9 works well):

warn: Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer[100]
      Unhandled exception rendering component: Method 'Boolean Contains(System.String)' declared on type 'System.String' cannot be called with instance of type 'System.Object'
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (27ms) [Parameters=[@t0='?' (DbType = DateTime), @t1='?' (DbType = DateTime), @f='?' (DbType = Int32), @sh='?' (Size = 9), @tzo='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
      SELECT [p].[ProductionParameterID], [p].[Timestamp], [p].[cycle_id], [p].[Duration], [p].[DurationWPayout], [p].[Name], [p].[ParameterSubType], [p].[ParameterType], [p].[Station], [p].[StationType], [p].[Value]
      FROM (
          select * from dbo.GetEventsPpdWithDetails(@t0, @t1, @f, @sh, @tzo)
      ) AS [p]
      ORDER BY [p].[Timestamp]
warn: Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer[100]
      Unhandled exception rendering component: Method 'Boolean Contains(System.String)' declared on type 'System.String' cannot be called with instance of type 'System.Object'
      System.ArgumentException: Method 'Boolean Contains(System.String)' declared on type 'System.String' cannot be called with instance of type 'System.Object'
         at System.Linq.Expressions.Expression.ValidateCallInstanceType(Type instanceType, MethodInfo method)
         at System.Linq.Expressions.Expression.ValidateMethodAndGetParameters(Expression instance, MethodInfo method)
         at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression arg0)
         at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
         at Radzen.QueryableExtension.GetExpression[T](ParameterExpression parameter, FilterDescriptor filter, FilterCaseSensitivity filterCaseSensitivity, Type type)
         at Radzen.QueryableExtension.Where[T](IQueryable`1 source, IEnumerable`1 filters, LogicalFilterOperator logicalFilterOperator, FilterCaseSensitivity filterCaseSensitivity)
         at Radzen.QueryableExtension.Where[T](IQueryable`1 source, IEnumerable`1 columns)
         at Radzen.Blazor.RadzenDataGrid`1.get_View()
         at Radzen.Blazor.RadzenDataGrid`1.LoadSettingsInternal(DataGridSettings settings)
         at Radzen.Blazor.RadzenDataGrid`1.OnAfterRenderAsync(Boolean firstRender)
fail: Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost[111]
      Unhandled exception in circuit '6UUOux80v8wTY3YKAhAO8ZhQJu4lpBwMhLKQ9FUut88'.
      System.AggregateException: One or more errors occurred. (Method 'Boolean Contains(System.String)' declared on type 'System.String' cannot be called with instance of type 'System.Object')
       ---> System.ArgumentException: Method 'Boolean Contains(System.String)' declared on type 'System.String' cannot be called with instance of type 'System.Object'
         at System.Linq.Expressions.Expression.ValidateCallInstanceType(Type instanceType, MethodInfo method)
         at System.Linq.Expressions.Expression.ValidateMethodAndGetParameters(Expression instance, MethodInfo method)
         at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression arg0)
         at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
         at Radzen.QueryableExtension.GetExpression[T](ParameterExpression parameter, FilterDescriptor filter, FilterCaseSensitivity filterCaseSensitivity, Type type)
         at Radzen.QueryableExtension.Where[T](IQueryable`1 source, IEnumerable`1 filters, LogicalFilterOperator logicalFilterOperator, FilterCaseSensitivity filterCaseSensitivity)
         at Radzen.QueryableExtension.Where[T](IQueryable`1 source, IEnumerable`1 columns)
         at Radzen.Blazor.RadzenDataGrid`1.get_View()
         at Radzen.Blazor.RadzenDataGrid`1.LoadSettingsInternal(DataGridSettings settings)
         at Radzen.Blazor.RadzenDataGrid`1.OnAfterRenderAsync(Boolean firstRender)
         --- End of inner exception stack trace ---

@Serge_Solntsev send us runnable code/details on how to replicate this.

To reproduce :
on Blazor DataGrid Component - Advanced Filter Mode | Free UI Components by Radzen
try filter on "First Name" column...
It breaks if two "Contains" are combined with "OR".
Also see screenshot from my app:

Thanks @Serge_Solntsev! Fixed in just published 6.0.5 version.

The intial problem was fixed, but now, there are even more issues with 6.0.5:

e.g. I assign the filter expression of a data grid for a query which is:

it => it.IsActive == True

This also breaks and says "invalid where clause".

Furthermore, I also add a Select for the query which is:

Select = "IsActive, (Account == null ? 0 : Account.AccountNo) as AccountNo, Comment"

This also makes the query crash once it gets executed.

Please use valid C# for expressions. This should be: it.IsActive == true.

This can be simplified to IsActive,Account.AccountNo,Comment

Thanks for the reply.

it.IsActive == True

This is the filter expression that I take from the DataGrid (myDataGrid.Query.Filter). So the DataGrid produces an incompatible filter expressions...

The issue with the select seems to be the "as" expressions. However, these are needed to make the output have the desired column names.

I'm unable to replicate such filter expression using our demos. Can you point us how/where?

There is not problem to use as - our exporting demo is using it:

I was able to replicate it! Will be fixed immediately.

I'm afraid that such conditions in dynamic Select cannot be supported anymore.

IQueryable does not contain a definition for 'ThenBy'

if (!string.IsNullOrEmpty(args.OrderBy))
{
    query = query.OrderBy(args.OrderBy)
        .ThenBy(o => o.OrderID);
}

Hey @nitrouscookies,

Not sure how this is related to the thread - can you clarify?

UPDATE: I think I know what's missing - we need to return IOrderedQueryable<>. We will update it!

1 Like

This worked previously, but is no longer available after upgrading to 6.0.*

I can handle it differently, I just thought I'd post it here in case the intention was for it to be continually supported.

@nitrouscookies Will be supported: OrderBy() should return IOrderedQueryable<T> ยท radzenhq/radzen-blazor@df121e6 ยท GitHub

Current version Radzen.Blazor 6.0.14.

Issue i'm experiencing is when using a Guid within the filter parameter being compared with a uniqueidentifier. I found 2 work around, but wondering if this is to be expected or if it indeed a bug. I leverage the cookie setting solution, but enhanced it to pull settings from a database while letting users save any number of "views" per datagrid. As such this filter is used on every datagrid within my application.

Error:

System.InvalidOperationException: 'Invalid predicate: i => i.CreatedById == (2d62d1cc-cde2-2222-aeda-2ad22afe2a22) && i.GridName == ("Orders")'

Inner Exception:
InvalidOperationException: No coercion operator is defined between types 'System.Double' and 'System.Guid'.

Original Code which broke after update:
savedViewsCollection = await P3PLService.GetSettingsSavedViews_Datagrid(new Query { Filter = $@"i => i.CreatedById = (@0) && i.GridName = (@1)", FilterParameters = new object { Guid.Parse(Security.User.Id), DatagridName}});

Work around 1:

savedViewsCollection = await P3PLService.GetSettingsSavedViews_Datagrid(new Query
{
Filter = $@"i => i.CreatedById.ToString() == (@0) && i.GridName == (@1)",
FilterParameters = new object { "2d62d1cc-cde2-2222-aeda-2ad22afe2a22", DatagridName }
});

Work aound 2:

savedViewsCollection = await P3PLService.GetSettingsSavedViews_Datagrid(new Query
{
Filter = $@"i => i.CreatedById.ToString() == (@0) && i.GridName == (@1)",
FilterParameters = new object { Guid.Parse(Security.User.Id).ToString(), DatagridName }
});

Indeed such strings are no longer supported since are not valid C#. We will do our best to provide fix for such code however:

savedViewsCollection = await P3PLService.GetSettingsSavedViews_Datagrid(new Query { Filter = $@"i => i.CreatedById = (@0) && i.GridName = (@1)", FilterParameters = new object { Guid.Parse(Security.User.Id), DatagridName}});

UPDATE: Support for such cases including Guid, DateTime, DateTimeOffset, DateOnly, and TimeOnly parameters fixed in just latest update. OrderBy with lambda expression as string fixed as well.