Pending Review
Last Updated: 08 Mar 2019 12:13 by ADMIN
Akesh Gupta
Created on: 01 Mar 2019 14:04
Category: Grid
Type: Feature Request
1
Add Grid Support for DynamicObject, currently setting Model.Id throws a type cast exception

When you create a Grid using a TModel that inherits from DynamicObject, a type cast exception is thrown when setting the DataSource Model Id property.

public class Metadata : DynamicObject

{ ... }  


...
.DataSource(dataSource =>
{
    dataSource.Ajax()
      .Model(model =>
      {
          model.Id("Id");
      });
})

A type cast exception is thrown by the following line in Kendo\AspNet.Core\Kendo.Mvc\UI\DataSource\Fluent\DataSourceModelDescriptorFactoryBase.cs because ModelDynamicDataKey is not generic, so it cannot be cast to IDataKey<TModel>

dataKey = (IDataKey<TModel>)new ModelDynamicDataKey(fieldName, lambdaExpression);


The following code changes fix the issue:

DataSourceModelDescriptorFactoryBase.cs

namespace Kendo.Mvc.UI.Fluent
{
	using System.Reflection;
	using Extensions;

	/// <summary>
	/// Defines the fluent interface for configuring the <see cref="DataSource"/> Model definition.
	/// </summary>
	/// <typeparam name="TModel">Type of the model</typeparam>
	public abstract class DataSourceModelDescriptorFactoryBase<TModel> : IHideObjectMembers
        where TModel : class
    {
        protected readonly ModelDescriptor model;

        public DataSourceModelDescriptorFactoryBase(ModelDescriptor model)
        {
            this.model = model;
        }

        /// <summary>
        /// Specify the member used to identify an unique Model instance.
        /// </summary>
        /// <param name="fieldName">The member name.</param>
        protected void Id(string fieldName)
        {
            IDataKey<TModel> dataKey;
            if (typeof(TModel).IsDynamicObject())
            {
                var lambdaExpression = ExpressionBuilder.Expression<TModel, object>(fieldName);
                dataKey = new ModelDynamicDataKey<TModel>(fieldName, lambdaExpression);
            }
            else
            {
                dataKey = GetDataKeyForField(fieldName);
            }

            dataKey.RouteKey = dataKey.Name;

            model.Id = dataKey;
        }

        protected IDataKey<TModel> GetDataKeyForField(string fieldName)
        {
            var lambdaExpression = ExpressionBuilder.Lambda<TModel>(fieldName);
            var fieldType = typeof(ModelDataKey<,>).MakeGenericType(new[] { typeof(TModel), lambdaExpression.Body.Type });

            var constructor = fieldType.GetConstructor(new[] { lambdaExpression.GetType() });

            return (IDataKey<TModel>)constructor.Invoke(new object[] { lambdaExpression });
        }
    }
}

 

ModelDynamicDataKey.cs

namespace Kendo.Mvc.UI
{
    using System;
    using System.Linq.Expressions;
    using Microsoft.AspNetCore.Mvc.Rendering;

    internal class ModelDynamicDataKey<TModel> : IDataKey<TModel>
        where TModel : class
    {
        public ModelDynamicDataKey(string memberName, Expression<Func<TModel, object>> expression)
        {
            RouteKey = "id";
            Name = memberName;
            Expression = expression;
            Value = expression.Compile();
        }

        public string Name
        {
            get;
        }

        public string RouteKey
        {
            get;
            set;
        }

        public Func<TModel, object> Value
        {
            get;
        }

        public Expression<Func<TModel, object>> Expression
        {
            get;
        }

        public object GetValue(object dataItem)
        {
            try
            {
                return Value((TModel)dataItem);
            }
            catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)
            {
                return null;
            }
        }

        public string HiddenFieldHtml(IHtmlHelper<TModel> htmlHelper)
        {
            return htmlHelper.Hidden(Name, null, new { id = "" }).ToString();
        }
    }
}


1 comment
ADMIN
Angel Petrov
Posted on: 08 Mar 2019 12:13
Hi,

I have already provided an answer in the official support ticket you have opened in regards of this. As mentioned there we do not fully support the use of DynamicObjects and such problems may occur. In order to include the suggested changes in our source code I would recommend opening a feature request and providing an exemplary use case.

Regards,
Angel Petrov
Progress Telerik
Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.