Setting rules in any method throws internal json deserialization exception

Hi There,

I am using a querybuilder component in my project, and while creating rules from scratch in the component works fine, setting rules through any method throws the following exception:

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot implicitly convert type 'System.Text.Json.JsonElement' to 'string'   at CallSite.Target(Closure , CallSite , Object )   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)   at Syncfusion.Blazor.QueryBuilder.Internal.QueryBuilderRules`1.SetField()   at Syncfusion.Blazor.QueryBuilder.Internal.QueryBuilderRules`1.OnParametersSetAsync()   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost: Error: Unhandled exception in circuit '8OzBvqX9F2DatOGOCDy0mQ9H43g3qH4cxECT6t7oEy8'.
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: Cannot implicitly convert type 'System.Text.Json.JsonElement' to 'string'   at CallSite.Target(Closure , CallSite , Object )   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)   at Syncfusion.Blazor.QueryBuilder.Internal.QueryBuilderRules`1.SetField()   at Syncfusion.Blazor.QueryBuilder.Internal.QueryBuilderRules`1.OnParametersSetAsync()   at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()


I have tried:

  1. Setting rules before component initialization:

                <SfQueryBuilder TValue="ExpandoObject" MaxGroupCount="0" @ref="queryBuilder">

                    <QueryBuilderRule Condition="and" Rules="@rules"></QueryBuilderRule>

(ExpandoObject type is being used as columns are created dynamicly in a foreach loop)

2. Setting rules after render with the "AddRule" method:

foreach (var rule in entityFilterView.entityFilterOptions.FilterRules)

                {

                    queryBuilder.AddRule(rule,"0");

                }

//This foreach loop is an object of type List<RuleModel>


It seems that there is an internal error in the component with json deserialization.  Your documentation is also very vague on how to import rules pre and post init without hardco


3 Replies

GK Gayathri KarunaiAnandam Syncfusion Team August 18, 2021 01:43 PM UTC

Hi HappyCamper, 

We have checked your reported query. We are unable to replicate the reported issue in our end. We have prepared a sample based on your requirement. Please check the code snippet. 
  
Code: 

<SfQueryBuilder TValue="ExpandoObject" @ref="QuerybuilderObj">   
 
    <QueryBuilderColumns>   
    @{    
        foreach(var column in columns)   
        {   
            <QueryBuilderColumn Field="@column.Field" Label="@column.Label" Type="@column.Type" Operators="@column.Operators"></QueryBuilderColumn>   
        }   
    }   
    </QueryBuilderColumns>   
</SfQueryBuilder>   
<SfButton @onclick="addRule" IsPrimary="true" Content="Add Rules"></SfButton> 
   
@code { 
     SfQueryBuilder<ExpandoObject> QuerybuilderObj; 
     
 
    RuleModel SampRule = new RuleModel() 
    { 
        Label = "Employee ID", 
        Field = "EmployeeID", 
        Type = "Number", 
        Operator = "equal", 
        Value = 1091 
    }; 
    private List<QueryBuilderColumn> columns = new(); 
 
    private static string[] Values = new string[] { "Mr.", "Mrs." };   
  
     public List<OperatorsModel> CustomOperators = new List<OperatorsModel> {  
        new OperatorsModel { Text="Equal", Value="equal"},  
        new OperatorsModel { Text="Not equal", Value="notequal"}  
    };  
  
    protected override async Task OnInitializedAsync()   
   
    {   
        columns = new List<QueryBuilderColumn>()   
    {   
        new QueryBuilderColumn(){ Field="EmployeeID", Label="Employee ID", Type=ColumnType.Number, Operators=CustomOperators},   
        new QueryBuilderColumn(){ Field="FirstName", Label="First Name", Type=ColumnType.String, Operators=CustomOperators},   
        new QueryBuilderColumn(){ Field="TitleOfCourtesy", Label="Title of Courtesy", Type=ColumnType.Boolean, Values=Values },   
   
    }; 
         
     
        await base.OnInitializedAsync();   
    }  
  private void addRule() 
    { 
        QuerybuilderObj.AddRule(SampRule, "0"); 
    } 
} 

For your reference, we have prepared a sample based on this. Please check the below link. 


If you are still facing the issue, kindly share the below details. 

  • If possible, try to reproduce the reported issue in provided sample or share the issue reproducible sample.
  • If possible, please share the video of the issue.
  • Please share the Syncfusion version you are using.

Please provide the above requested information, based on that we will check and provide you a better solution quickly. 

Regards, 
Gayathri K 



HA HappyCamper August 18, 2021 07:13 PM UTC

Hi Gayathri,

The flow of my page/ component is:

OnAfterRenderAsync  : (This is done in the OnAfterRenderAsync Task to not stall the UI of the user on initialization as there is a webapi being called)


  1. Build the columns
  2. Render the columnds and the query component
  3. Call Webapi to get the rules, and load the rules.  My webapi returns a List<RuleModel>.


The user cannot click a button to retrieve their rules from the database.  This is an "edit query" page that edits queries persisted to a database.

The main problem here is that it seems that this cannot be done in a loading "flow"...  I have attached a mock up project that simulates the same behaviour and the rules not being populated.




Attachment: querybuildertest_(2)_cc0123cb.zip


GK Gayathri KarunaiAnandam Syncfusion Team August 19, 2021 02:24 PM UTC

Hi HappyCamper, 

We have checked your reported query. We can render Rules in Querybuilder on initialization method OnAfterRenderAsync. We have prepared a sample based on your requirement. Please check the below code snippet. 

 
@if (Columns != null) 
{  
    <SfQueryBuilder TValue="string[]" MaxGroupCount="0" @ref="queryBuilderobj"> 
        <QueryBuilderRule Rules="ruleModels" Condition="and"></QueryBuilderRule> 
        <QueryBuilderColumns> 
            @foreach (var col in Columns) 
            { 
                <QueryBuilderColumn Field="@col.Field" Label="@col.Label" Type="@col.Type" Operators="@cOperators"></QueryBuilderColumn> 
 
            } 
        </QueryBuilderColumns> 
    </SfQueryBuilder> 
} 
 
 
<div>Test Param:  @TestParam</div> 
 
@code{ 
 
    [Parameter] public string TestParam { get; set; } 
    SfQueryBuilder<string[]> queryBuilderobj; 
 
    private List<QueryBuilderColumn> Columns { get; set; } 
 
     List<RuleModel> ruleModels = new(); 
 
 
    public List<OperatorsModel> cOperators = new List<OperatorsModel> { 
        new OperatorsModel { Text="Equal", Value="equal"}, 
        new OperatorsModel { Text="Not equal", Value="notequal"} 
    }; 
 
 
    protected override async Task OnAfterRenderAsync(bool firstRender) 
    { 
        if (firstRender) 
        { 
 
            //At this point webapi will be called that returns a a List<RuleModel> object and the columns that is supported.   
            //The below simulates that webapi call. 
 
            Columns = new() { 
                new QueryBuilderColumn { Field = "Name", Label = "Name", Operators = cOperators, Type = ColumnType.String }, 
                new QueryBuilderColumn { Field = "Email", Label = "Email", Operators = cOperators, Type = ColumnType.String } 
            }; 
 
 
            StateHasChanged(); 
             
 
            var rule = new RuleModel(); 
            rule.Field = "Name"; 
            rule.Label = "Name"; 
            rule.Type = "String"; 
            rule.Operator = "equal"; 
            rule.Value = "test 123"; 
 
            ruleModels.Add(rule); 
 
            var rule2 = new RuleModel(); 
            rule2.Field = "Email"; 
            rule2.Label = "Email"; 
            rule2.Type = "String"; 
            rule2.Operator = "notequal"; 
            rule2.Value = [email protected]; 
 
            ruleModels.Add(rule2); 
 
            var rule3 = new RuleModel(); 
            rule3.Field = "Name"; 
            rule3.Label = "Name"; 
            rule3.Type = "String"; 
            rule3.Operator = "equal"; 
            rule3.Value = "test_123"; 
             ruleModels.Add(rule3); 
 
            StateHasChanged(); 
        }    
    } 
} 

For your convenience, we have modified your sample. Please check the below link. 


Please get back to us, if you need further assistance. 

Regards, 
Gayathri K 


Loader.
Up arrow icon