Всем привет!
Есть для автомаппера библиотека, позволяющая работать с OData. Суть ее в том, что она сама прописывает инклуды, фильтры и прочее через переданный в синтаксисе OData запрос.
В моей системе есть роли, и один и тот же метод используется для получения разного объема информации.
Собственно вся задача в том, что я хочу вешать на объекты кастомные атрибуты, например -
[NotMapWhenNotInRole(Role.User)]
и после чего позволять в
Select
относить только те свойства, которые разрешены атрибутом
Я методом дебага и рантайма выловил нужные мне типы выражений, но вот самая ключевая проблема их модифицировать. Метод-то я написал, но выглядит он крайне ненадежно и колхозно.
С expression trees я только знакомлюсь, эта задача одна из типовых (которые буду применять лично я)
А вот собственно метод
public static IQueryable<T> ODataMapFromRoles<T>(this IQueryable<T> query, List<Role> roles)
{
var dt1 = query.Expression as MethodCallExpression;
var dt2 = dt1!.Arguments.OfType<UnaryExpression>().First();
var dt3 = dt2.Operand as LambdaExpression;
// Задача решилась бы очень просто если для переменной dt4 можно было выставить параметр Bindings. Однако он readonly!
var dt4 = dt3!.Body as MemberInitExpression;
return query.Provider.CreateQuery<T>(Expression.Call(dt1.Method ,dt1.Arguments.OfType<EntityQueryRootExpression>().First(),
Expression.MakeUnary(dt2.NodeType, Expression.Lambda(Expression.MemberInit(dt4.NewExpression, new List<MemberBinding>()), dt3.Parameters), dt2.Type, dt2.Method)));
return query;
}
Используется примерно так
return await _dbContext.Accounts.GetQuery(_mapper, query).ODataMapFromRoles(_authStorage.CurrentRoles).ToListAsync(token);
По большей части вопрос в том, как это сделать грамотно? Селект может быть вполне себе вложенный, а значит и глубина вложенности экспрешена может быть бесконечной -
не доставать ж мне каждый экспрешен и опрокидывать его