Hello everyone,
I have been struggling for days over an old (2011) piece of C# code I extracted from a DLL my boss wants me to edit.
The application queries a database with LINQ, server-side processes it and displays the data with a DataTable.
From what I gathered, the guy who wrote it had created an ASP.NET Web Forms Site in Visual Studio 2010, with .NET Framework 4.0.
He used the server-side parser from Zack Owens.
In the project I recreated in VS 2017, everything builds well, but at runtime, a bug comes from the little customizations he made to the DataTable parser: among them, the SelectProperties() function has been completely rewritten from this:
private Expression<Func<T, List<string>>> SelectProperties
{
get
{
return value => _properties.Select
(
// empty string is the default property value
prop => (prop.GetValue(value, new object[0]) ?? string.Empty).ToString()
)
.ToList();
}
}
to this:
private Expression<Func<T, List<string>>> SelectProperties
{
get
{
var parameterExpression = Expression.Parameter(typeof(T), "value");
// (Edited) The bug happens there: type_RD is null because GetMethod is not valid
var type_RD = typeof(Enumerable).GetMethod(
"ToList",
new Type[] {
typeof(IEnumerable<string>)
}
);
// The program crashes there (System.Null.Exception)
var methodFromHandle = (MethodInfo)MethodBase.GetMethodFromHandle(
type_RD
.MethodHandle);
var expressionArray = new Expression[1];
var methodInfo = (MethodInfo)MethodBase.GetMethodFromHandle(
typeof(Enumerable).GetMethod("Select", new Type[] {
typeof(IEnumerable<PropertyInfo>),
typeof(Func<PropertyInfo, string>)
})
.MethodHandle);
var expressionArray1 = new Expression[] {
Expression.Field(
Expression.Constant(
this,
typeof(DataTableParser<T>)
),
FieldInfo.GetFieldFromHandle(
typeof(DataTableParser<T>).GetField("_properties").FieldHandle,
typeof(DataTableParser<T>).TypeHandle
)
), null
};
var parameterExpression1 = Expression.Parameter(
typeof(PropertyInfo),
"prop"
);
var methodFromHandle1 = (MethodInfo)MethodBase.GetMethodFromHandle(
typeof(PropertyInfo).GetMethod(
"GetValue",
new Type[] {
typeof(object),
typeof(object[])
}
)
.MethodHandle);
var expressionArray2 = new Expression[] {
Expression.Convert(
parameterExpression,
typeof(object)
),
Expression.NewArrayInit(
typeof(object),
new Expression[0]
)
};
var methodCallExpression = Expression.Call(
Expression.Coalesce(
Expression.Call(
parameterExpression1,
methodFromHandle1,
expressionArray2
),
Expression.Field(
null,
FieldInfo.GetFieldFromHandle(
typeof(string).GetField("Empty").FieldHandle
)
)
),
(MethodInfo)MethodBase.GetMethodFromHandle(
typeof(object).GetMethod("ToString").MethodHandle
),
new Expression[0]
);
expressionArray1[1] = Expression.Lambda<Func<PropertyInfo, string>>(
methodCallExpression,
parameterExpression1
);
expressionArray[0] = Expression.Call(
null,
methodInfo,
expressionArray1
);
// Return Lambda
return Expression.Lambda<Func<T, List<string>>>(
Expression.Call(
null,
methodFromHandle,
expressionArray
),
parameterExpression
);
}
}
My questions:
- How to make the SelectProperties function work?
- What exactly is its purpose? I didn't get any of the "MethodHandle" bits ...
The only hint I have is that, when I use the original SelectProperties code, the data are in the wrong columns and the sorting causes errors 500 with some of the columns.
Here is the other customized function of this custom DataTable.cs parser:
public FormatedList<T> Parse()
{
var list = new FormatedList();
list.Import(_properties.Select(x => x.Name).ToArray());
list.sEcho = int.Parse(_httpRequest[ECHO]);
list.iTotalRecords = _queriable.Count();
ApplySort();
int skip = 0, take = 10;
int.TryParse(_httpRequest[DISPLAY_START], out skip);
int.TryParse(_httpRequest[DISPLAY_LENGTH], out take);
/* (Edited)
list.aaData = _queriable.Where(ApplyGenericSearch)
.Where(IndividualPropertySearch)
.Skip(skip)
.Take(take)
.Select(SelectProperties)
.ToList();
list.iTotalDisplayRecords = list.aaData.Count;
*/
list.aaData = _queriable.Where(ApplyGenericSearch)
.Where(IndividualPropertySearch)
.Skip(skip)
.Take(take)
.ToList()
.AsQueryable()
.Select(SelectProperties)
.ToList();
list.iTotalDisplayRecords = list.iTotalRecords;
return list;
}
I am a beginner at C#, .NET, Linq etc., though I know quite a few other languages.
Setup: Windows 7 64, Visual Studio 2017.
Thank you for your help!