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();
}
}
}