I have a Kendo jquery DropdownList with Server Filtering.
var personnelId = $('#PersonnelId').val();
$("#drpPersonnel").kendoDropDownList({
optionLabel: "Select...",
filter: "contains",
dataTextField: "FullName",
dataValueField: "Id",
change: function (e) {
$('#PersonnelId').val(this.value());
},
autoBind: true,
dataSource: {
serverFiltering: true,
transport: {
read: {
headers: {
"__RequestVerificationToken": $('input[name=__RequestVerificationToken]').val()
},
type: "Post",
dataType: "json",
url: "/Base/User/GetAllPersonnel"
}
}
}
}).data("kendoDropDownList").value(personnelId);
I am using the following DataSourceRequest Model to binding filters, paging, sorting, and other options from Kendo-UI Components.
public class DataSourceRequest
{
/// <summary>
/// Specifies how many items to take.
/// </summary>
public int Take { get; set; }
/// <summary>
/// Specifies how many items to skip.
/// </summary>
public int Skip { get; set; }
/// <summary>
/// Specifies the requested sort order.
/// </summary>
public IEnumerable<Sort> Sort { get; set; }
/// <summary>
/// Specifies the requested filter.
/// </summary>
public Filter Filter { get; set; }
}
Filter:
/// <summary>
/// Represents a filter expression of Kendo DataSource.
/// </summary>
[DataContract]
public class Filter
{
/// <summary>
/// Gets or sets the name of the sorted field (property). Set to <c>null</c> if the <c>Filters</c> property is set.
/// </summary>
[DataMember(Name = "field")]
public string Field { get; set; }
/// <summary>
/// Gets or sets the filtering operator. Set to <c>null</c> if the <c>Filters</c> property is set.
/// </summary>
[DataMember(Name = "operator")]
public string Operator { get; set; }
/// <summary>
/// Gets or sets the filtering value. Set to <c>null</c> if the <c>Filters</c> property is set.
/// </summary>
[DataMember(Name = "value")]
public object Value { get; set; }
/// <summary>
/// Gets or sets the filtering logic. Can be set to "or" or "and". Set to <c>null</c> unless <c>Filters</c> is set.
/// </summary>
[DataMember(Name = "logic")]
public string Logic { get; set; }
/// <summary>
/// Gets or sets the child filter expressions. Set to <c>null</c> if there are no child expressions.
/// </summary>
[DataMember(Name = "filters")]
public IEnumerable<Filter> Filters { get; set; }
/// <summary>
/// Mapping of Kendo DataSource filtering operators to Dynamic Linq
/// </summary>
private static readonly IDictionary<string, string> operators = new Dictionary<string, string>
{
{"eq", "="},
{"neq", "!="},
{"lt", "<"},
{"lte", "<="},
{"gt", ">"},
{"gte", ">="},
{"startswith", "StartsWith"},
{"endswith", "EndsWith"},
{"contains", "Contains"},
{"doesnotcontain", "Contains"}
};
/// <summary>
/// Get a flattened list of all child filter expressions.
/// </summary>
public IList<Filter> All()
{
var filters = new List<Filter>();
Collect(filters);
return filters;
}
private void Collect(IList<Filter> filters)
{
if (Filters != null && Filters.Any())
{
foreach (Filter filter in Filters)
{
filters.Add(filter);
filter.Collect(filters);
}
}
else
{
if (!filters.Select(s => s.Value).Equals(this.Value) && !filters.Select(s => s.Field).Equals(this.Field))
{
if (filters.Any(x => x.Field != this.Field && x.Value != this.Value))
{
filters.Add(this);
}
}
}
}
/// <summary>
/// Converts the filter expression to a predicate suitable for Dynamic Linq e.g. "Field1 = @1 and Field2.Contains(@2)"
/// </summary>
/// <param name="filters">A list of flattened filters.</param>
public string ToExpression(IList<Filter> filters)
{
if (Filters != null && Filters.Any())
{
return "(" + String.Join(" " + Logic + " ", Filters.Select(filter => filter.ToExpression(filters)).ToArray()) + ")";
}
int index = filters.IndexOf(this);
string comparison = operators[Operator.ToLower()];
if (Operator == "doesnotcontain")
{
return String.Format("!{0}.{1}(@{2})", Field, comparison, index);
}
if (comparison == "StartsWith" || comparison == "EndsWith" || comparison == "Contains")
{
return String.Format("{0}.{1}(@{2})", Field, comparison, index);
}
return String.Format("{0} {1} @{2}", Field, comparison, index);
}
}
Each filter in IEnumerable<Filter> Filters can have a value with a different type such as string, string[] and int. For this reason, Value property is an object type. It's working fine with Kendo-Grid but with Kendo Dropdownlist this value is null.
It should be noted that if I change the Value property type to string, it's work.
This is how I'm using DataSourceRequest and System.Linq.Dynamic.Core. The Value as object convert to other types depend on field that comes in where clause in the query.
public async Task<DataSourceResult> GetAllPersonnel(DataSourceRequest request, CancellationToken cancellationToken = default(CancellationToken))
{
try
{
IQueryable<Personnel> query = _dbSetPersonnel.AsNoTracking();
if (request.Filter != null && request.Filter.Logic != null)
{
var filters = request.Filter.All().Where(c => c.Value != null).ToList();
if (filters.Count > 0)
{
foreach (var filter in filters)
{
Type valueType = filter.Value.GetType();
if (valueType.IsArray)
{
filter.Value = ((string[])(filter.Value)).First();
}
if (filter.Field == "ContactNo")
{
bool hasContactFilter = int.TryParse(filter.Value.ToString(), out int contactNo);
filter.Value = contactNo;
}
}
var values = filters.Select(f => f.Value).ToArray();
request.Filter.Filters = request.Filter.Filters.Where(x => x.Value != null);
string predicate = (request.Filter).ToExpression(filters);
predicate = predicate.Replace("StateName", "City.State.Name");
predicate = predicate.Replace("CityName", "City.Name");
query = query.Where(predicate, values);
}
}
var total = await query.CountAsync(cancellationToken);
if (request.Sort != null && request.Sort.Any())
{
var ordering = string.Join(",", request.Sort.Select(s => s.ToExpression()));
ordering = ordering.Replace("StateName", "City.State.Name");
ordering = ordering.Replace("CityName", "City.Name");
query = query.OrderBy(ordering);
}
else
{
query = query.OrderBy(c => c.LastName);
}
query = query.Skip(request.Skip).Take(request.Take);
var list = await query.ToListAsync(cancellationToken);
List<PersonnelViewModel> viewModel = new List<PersonnelViewModel>();
_mapper.Map<List<Personnel>, List<PersonnelViewModel>>(list, viewModel);
return new DataSourceResult
{
Data = viewModel,
Total = total
};
}
catch (Exception ex)
{
throw;
}
}
I need to know how can bind object type to action in .net core, If anyone suggests another approach to solve the problem, please let me know.

