I am taking an existing project and adding KendoUI in place of Grid's by another vendor.
The project uses IoC, UnitOfWork etc and so the MVC controllers do not directly use the Context and I cannot see the ToDataSourceResult method.
I have got it mostly working using .Server(), but now want to start using Ajax.
What does ToDataSourceResult do, and how can I replicate its functionality?
1 Answer, 1 is accepted
The ToDataSourceResult is an IEnumerable(IQueryable) extension method and you should include the Kendo.Mvc.Extensions namespace in order to use it. For more detailed information, check the Ajax binding documentation topic.
Regards,Daniel
the Telerik team
For example, overrides on ToDataSourceResult - you have zero doc's that I can find on them - with examples.
They're improving their documentation all the time but they just released the MVC extensions not too long ago so it'll probably take them some time to get those up to speed.
If you have specific questions though, the guys are usually pretty good with their support tickets and stuff. I've hit them up about the stupidest things at 5PM when my brain is fried and usually have tickets taken care of with code samples, etc the next day for the most part...
public class Product{ public long Product_Id; public string Product_Name;}And a simple ViewModel like:
public class ProductVM{ public long ProductId; public string ProductName;}When filtering on the ProductName (a ViewModel property) in the grid on the webpage, I get an ArgumentException like : "Invalid property or field - 'ProductName' for type: Product" when I call the code :
var result = products.ToDataSourceResult(request, model => AutoMapper.Mapper.Map<ProductVM>(model));Is there an easy way or an extension method available to change the filter based on the AutoMapper defined mapping, or should I just write my own method to modify the filters ?
public static class DataSourceRequestExtension { public static DataSourceRequest Remap(this DataSourceRequest Request, Type TSource, Type TDestination) { Request.Sorts = RemapSort(Request.Sorts, TSource, TDestination); Request.Filters = RemapFilter(Request.Filters, TSource, TDestination); return Request; } private static IList<Kendo.Mvc.SortDescriptor> RemapSort(IList<Kendo.Mvc.SortDescriptor> Sorts, Type TSource, Type TDestination) { if (Sorts != null) { // Get currently mapped properties for the source and destination types List<AutoMapper.PropertyMap> propertyMaps = AutoMapper.Mapper.FindTypeMapFor(TSource, TDestination).GetPropertyMaps().ToList(); foreach (AutoMapper.PropertyMap propertyMap in propertyMaps) { // We are only interested in custom expressions because they do not map field to field if (propertyMap.CustomExpression != null) { // Get the linq expression body string body = propertyMap.CustomExpression.Body.ToString(); // Get the item tag string tag = propertyMap.CustomExpression.Parameters[0].Name; Regex regex = new Regex(string.Format("{0}.", tag)); string destination = regex.Replace(body, string.Empty, 1); string source = propertyMap.DestinationProperty.Name; // Go throug each sort and update foreach (Kendo.Mvc.SortDescriptor sort in Sorts) { if (sort.Member.ToLower().Equals(source.ToLower())) { sort.Member = destination; } } } } } return Sorts; } private static IList<Kendo.Mvc.IFilterDescriptor> RemapFilter(IList<Kendo.Mvc.IFilterDescriptor> Filters, Type TSource, Type TDestination) { if (Filters != null) { // Get currently mapped properties for the source and destination types List<AutoMapper.PropertyMap> propertyMaps = AutoMapper.Mapper.FindTypeMapFor(TSource, TDestination).GetPropertyMaps().ToList(); foreach (AutoMapper.PropertyMap propertyMap in propertyMaps) { // We are only interested in custom expressions because they do not map field to field if (propertyMap.CustomExpression != null) { // Get the linq expression body string body = propertyMap.CustomExpression.Body.ToString(); // Get the item tag string tag = propertyMap.CustomExpression.Parameters[0].Name; string destination = body.Replace(string.Format("{0}.", tag), string.Empty); string source = propertyMap.DestinationProperty.Name; // Go throug each sort and update foreach (Kendo.Mvc.IFilterDescriptor filter in Filters) { if (filter is CompositeFilterDescriptor) { ProcessCompositeFilter((CompositeFilterDescriptor)filter, source, destination); } if (filter is FilterDescriptor) { if (((FilterDescriptor)filter).Member.ToLower().Equals(source.ToLower())) { ((FilterDescriptor)filter).Member = destination; } } } } } } return Filters; } private static void ProcessCompositeFilter(CompositeFilterDescriptor filter, string source, string destination) { foreach (Kendo.Mvc.IFilterDescriptor subFilter in filter.FilterDescriptors) { if (subFilter is CompositeFilterDescriptor) { ProcessCompositeFilter((CompositeFilterDescriptor)subFilter, source, destination); } else { Kendo.Mvc.FilterDescriptor filterDescriptor = (Kendo.Mvc.FilterDescriptor)subFilter; if (filterDescriptor.Member.ToLower().Equals(source.ToLower())) { filterDescriptor.Member = destination; } } } } }Not quite sure you can do this out of the box. I have to name all my properties exactly the same, otherwise, nothing works. Check this out though, we've used it and seems to better in that case. Only iterates though filters and sorts though, no aggregates and group support:
No support for aggregates and group support yet...
using System;using System.Linq;using System.Collections.Generic;using AutoMapper;using Kendo.Mvc;using Kendo.Mvc.UI; namespace KendoUIMvcApplication1{ public static class MyDataSourceRequestExtensions { public static void ReMap<TSource, TDestination>(this DataSourceRequest request) { var mappings = GetPropertyMappings(new Dictionary<string, string>(), typeof(TSource), typeof(TDestination)); MapFilterDescriptors<TSource, TDestination>(mappings, request.Filters); MapSortDescriptors(mappings, request.Sorts); } private static IDictionary<string, string> GetPropertyMappings(IDictionary<string, string> mappings, Type sourceType, Type destinationType) { var map = Mapper.FindTypeMapFor(sourceType, destinationType); // We are only interested in custom expressions because they do not map field to field foreach (var propertyMap in map.GetPropertyMaps().Where(pm => pm.CustomExpression != null)) { // Get the linq expression body string body = propertyMap.CustomExpression.Body.ToString(); // Get the item tag string tag = propertyMap.CustomExpression.Parameters[0].Name; string destination = body.Replace(string.Format("{0}.", tag), string.Empty); string source = propertyMap.DestinationProperty.Name; mappings.Add(source, destination); } return mappings; } private static void MapFilterDescriptors<TModel, TResult>(IDictionary<string, string> mappings, IEnumerable<IFilterDescriptor> filters) { foreach (var filter in filters) { if (filter is FilterDescriptor) { var normalFilter = (FilterDescriptor)filter; if (mappings.ContainsKey(normalFilter.Member)) { normalFilter.Member = mappings[normalFilter.Member]; } } else if (filter is CompositeFilterDescriptor) { var compositeFilter = (CompositeFilterDescriptor)filter; MapFilterDescriptors<TModel, TResult>(mappings, compositeFilter.FilterDescriptors); } } } private static void MapSortDescriptors(IDictionary<string, string> mappings, IEnumerable<SortDescriptor> sortDescriptors) { foreach (var sortDescriptor in sortDescriptors) { string sourceMemberName = sortDescriptor.Member; if (mappings.ContainsKey(sourceMemberName)) { sortDescriptor.Member = mappings[sourceMemberName]; } } } }}Hello Steve,
If you have concerns about out support services I suggest you either open a private ticket, or email me directly at marin <dot> bratanov <at> telerik <dot> com so we can review the situation privately instead of diluting this thread.
I would only like to point out that the guaranteed response time for private tickets is 24 hours during business days (Mon-Fri), as noted in the Support Plans for DevTools page.
Regards,
Here you go Telerik. I'm surprised you don't offer this given the countless developers who map to flattened view models
The following Extension method to DataSourceRequest will allow flattened members to be renamed to their corresponding database member.
Example: request.RemapMember("ChildObjectName", "ChildObject.Name");
Send me an email and we can chat about you using my code officially... :)
public static class DataSourceRequestExtensions
{
public static void RemapMember(this DataSourceRequest request, string memberName, string newMemberName)
{
foreach (var sort in request.Sorts)
{
if (sort.Member.Equals(memberName))
{
sort.Member = newMemberName;
}
}
foreach (var filter in request.Filters)
{
if (filter is CompositeFilterDescriptor compositeFilterDescriptor)
{
foreach (var compositeFilter in compositeFilterDescriptor.FilterDescriptors)
{
RemapFilterDescription(compositeFilter, memberName, newMemberName);
}
}
RemapFilterDescription(filter, memberName, newMemberName);
}
}
private static void RemapFilterDescription(IFilterDescriptor filter, string memberName, string newMemberName)
{
if (!(filter is FilterDescriptor descriptor)) return;
if (descriptor.Member.Equals(memberName))
{
descriptor.Member = newMemberName;
}
}
Hello,
Generally there are plenty of solutions for remapping models. It is up to the developer to choose how to implement this. We do not plan to include this in our source for now. If we do at some point we will need to examine all the cases so we could ensure that there is not functionality that is left out.
Regards,
Angel Petrov
Progress Telerik
Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.