ToDataSourceResult

11 posts, 0 answers
  1. Simon831
    Simon831 avatar
    36 posts
    Member since:
    Sep 2005

    Posted 16 Aug 2012 Link to this post

    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?

  2. Daniel
    Admin
    Daniel avatar
    1511 posts
    Member since:
    Sep 2012

    Posted 21 Aug 2012 Link to this post

    Hello,

    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
    Join us on our journey to create the world's most complete HTML 5 UI Framework - download Kendo UI now!

  3. Shawn
    Shawn avatar
    4 posts
    Member since:
    Apr 2008

    Posted 11 Oct 2012 Link to this post

    I'm continually fascinated how poor documentation is on the MVC side of things with Kendo.  Poor examples, limited, lack of readable documentation.

    For example, overrides on ToDataSourceResult - you have zero doc's that I can find on them - with examples.

  4. Vesselin Obreshkov
    Vesselin Obreshkov avatar
    81 posts
    Member since:
    Jan 2010

    Posted 11 Oct 2012 Link to this post

    Yeah, the MVC extensions lack documentation a little bit. The ToDataSourceResult is simply an IQueryable extension that translates and handles filtering, sorting, grouping and aggregates. It works together with DataSourceRequest and can also handle projections for you (myIQueryable.ToDataSourceResult<TSource, TDestination>(request, model => AutoMapper.Mapper.Map<TSource, TDestination>(model)) which is pretty cool - we use it all the time. Go download Telerik JustDecompile and explore away I guess - this is how we had to figure out a lot of it to integrate with our own stuff.



    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...

  5. Shawn
    Shawn avatar
    4 posts
    Member since:
    Apr 2008

    Posted 11 Oct 2012 Link to this post

    yes, reflecting via dotPeek/Reflector has been the only way right now.  I haven't tried teleriks tool yet.  I hate mucking up VS with all those add-ins.

  6. Vesselin Obreshkov
    Vesselin Obreshkov avatar
    81 posts
    Member since:
    Jan 2010

    Posted 11 Oct 2012 Link to this post

    Reflecting, sorry... and you don't need to install any VSExtensions - you just need to include Kendo.Mvc.dll in your project and you're good to go (they have a -vsdoc for the .js files too). On my work VM, the only Telerik extension I have installed is JustCode which has nothing to do with Kendo. I have the whole suite on my "play" box and no issues there honestly. Only thing is JustCode has a conflict with the Productivity Power Tools by MS if you use that one - need to tweak some type assistance settings.

  7. Stef Heyenrath
    Stef Heyenrath avatar
    14 posts
    Member since:
    Dec 2009

    Posted 15 Oct 2012 Link to this post

    I've a simple database model class like:

    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));
    which is logical because the database model class (Product) does not contain the property ProductName but only Product_Name.

    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 ?

  8. Vesselin Obreshkov
    Vesselin Obreshkov avatar
    81 posts
    Member since:
    Jan 2010

    Posted 15 Oct 2012 Link to this post

    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:

  9. Stef Heyenrath
    Stef Heyenrath avatar
    14 posts
    Member since:
    Dec 2009

    Posted 15 Oct 2012 Link to this post

    I've created this code which has less code and uses more recursion. Can you verify if my code covers the same functionality ?
    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];
                    }
                }
            }
        }
    }

  10. Vesselin Obreshkov
    Vesselin Obreshkov avatar
    81 posts
    Member since:
    Jan 2010

    Posted 17 Oct 2012 Link to this post

    Well I'm not a human compiler so I can't tell you how well that code will work (or not). One thing I'll say though is you don't want to do much recursion of the data that you present to your client. You should be using flattened ViewModels whenever possible and don't do any recursion on there if possible. Specifically if you use JSON/AJAX binding.

  11. Tom
    Tom avatar
    1 posts
    Member since:
    Feb 2013

    Posted 19 Oct 2013 Link to this post

    Can you please provide example for use of this code

Back to Top