C# 使用Unity拦截的Linq到SQL
我在存储库模式中使用带有Unity的LINQtoSQL。我试图在存储库方法C# 使用Unity拦截的Linq到SQL,c#,linq-to-sql,unity-container,interceptor,C#,Linq To Sql,Unity Container,Interceptor,我在存储库模式中使用带有Unity的LINQtoSQL。我试图在存储库方法[Securable]IQueryable List()上添加一个对象安全拦截器,该方法拦截调用并仅返回用户有权访问的实体 public class SecurableAttribute : HandlerAttribute {...} public class SecurableHandler : ICallHandler { ... IMethodReturn Invoke(IMethodInvoca
[Securable]IQueryable List()
上添加一个对象安全拦截器,该方法拦截调用并仅返回用户有权访问的实体
public class SecurableAttribute : HandlerAttribute
{...}
public class SecurableHandler : ICallHandler
{
...
IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
var message = getNext()(input, getNext);
var returnType = message.ReturnValue.GetType();
if (typeof(IQueryable).IsAssignableFrom(returnType))
{
var entityType = returnType.GetGenericArguments().Single();
var securableAttribute = entityType.GetAttribute<SecurableTypeAttribute>();
if(securableAttribute != null)
{
//Build expression to filter the list from the attribute and primary key of the entity
//Return the new IQueryable
}
}
return message;
}
}
在实体上,它将我锁定在一点内,但是如果我可以分离其余的安全方面,我可以接受。这允许我在IMethodReturn Invoke(imethodindivation输入,GetNextHandlerDelegate getNext)
中执行以下操作,其中我构建了上面的表达式:
if(typeof(ISecurableType).IsAssignableFrom(entityType))
{
var secured = ((IQueryable<ISecurable>)message.ReturnValue).Where(expression);
//Need to return secured as IQueryably<TEntity>
}
if(typeof(ISecurableType).IsAssignableFrom(entityType))
{
var secured=((IQueryable)message.ReturnValue)。其中(表达式);
//需要安全返回,如有必要
}
我现在必须将secured
转换为IQueryable
但typeof(IQueryable)。IsAssignableFrom(secured.GetType())
返回false,交换返回值会引发异常,但就我所知,它似乎确实适用于延迟执行。(另外,我不知道在SecurableHandler
中设计时的tenty,但我知道反射类型-但我已经尝试使用类声明,我知道它正在测试中。)
有没有办法修改返回结果?我一直需要返回一个在设计时不知道的泛型,因此这是不可能的,但我也不能修改表达式(((IQueryable)message.ReturnType)。表达式
声明为表达式{get;}
)
有没有什么才华横溢的东西可以为我指明一条可行的道路
tl;dr需要在运行时从
对象
返回一个IQueryable
,该对象是一个表:IQueryable
,带有一个附加的。其中(表达式)
您可以尝试在运行时创建一个动态表达式。只要不使用“Select”更改元素类型,就不必显式地将IQueryable强制转换回它的泛型类型
例如:
public class SecurityHandler : ICallHandler
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
var message = getNext()(input, getNext);
var returnType = message.ReturnValue.GetType();
if (typeof(IQueryable).IsAssignableFrom(returnType))
{
var entityType = returnType.GetGenericArguments().Single();
var securableAttribute = entityType.GetAttribute<SecurableTypeAttribute>();
if (securableAttribute != null)
{
//Build expression to filter the list from the attribute and primary key of the entity
//Return the new IQueryable
message.ReturnValue = AddWhereExpression(
(IQueryable)message.ReturnValue,
securableAttribute.FilterValues,
securableAttribute.FilterPropertyName);
}
}
return message;
}
public int Order { get; set; }
private static IQueryable AddWhereExpression(IQueryable query, IEnumerable ids, string filterPropertyName)
{
// Build this expression:
// item => ids.Contains(item.[PrimaryKeyPropertyName])
var itemParameter = Expression.Parameter(query.ElementType, "item");
var itemParameterProperty = Expression.Property(itemParameter, filterPropertyName);
var listParameter = Expression.Constant(ids);
var containsExpression = Expression.Call(
typeof(System.Linq.Enumerable),
"Contains",
new[] { typeof(int) },
listParameter,
itemParameterProperty);
var delegateTypeExpression = Expression.GetFuncType(new[] { query.ElementType, typeof(bool) });
var whereExpression = Expression.Lambda(
delegateTypeExpression,
containsExpression,
new[] { itemParameter }
);
Expression callWhere = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { query.ElementType }, // type args for Where<T>()
query.Expression,
whereExpression
);
return query.Provider.CreateQuery(callWhere);
}
}
public类SecurityHandler:ICallHandler
{
公共IMethodReturn调用(IMethodInvoke输入,GetNextHandlereGate getNext)
{
var message=getNext()(输入,getNext);
var returnType=message.ReturnValue.GetType();
if(typeof(IQueryable).IsAssignableFrom(returnType))
{
var entityType=returnType.GetGenericArguments().Single();
var securableAttribute=entityType.GetAttribute();
if(securableAttribute!=null)
{
//生成表达式以从实体的属性和主键筛选列表
//返回新的IQueryable
message.ReturnValue=addWhere表达式(
(IQueryable)message.ReturnValue,
securableAttribute.FilterValues,
securableAttribute.FilterPropertyName);
}
}
返回消息;
}
公共整数顺序{get;set;}
专用静态IQueryable AddWhere表达式(IQueryable查询、IEnumerable ID、字符串filterPropertyName)
{
//构建此表达式:
//item=>ids.Contains(item.[PrimaryKeyPropertyName])
var itemParameter=Expression.Parameter(query.ElementType,“item”);
var itemParameterProperty=Expression.Property(itemParameter,filterPropertyName);
var listParameter=表达式常数(ID);
var containsExpression=Expression.Call(
类型(系统级别可枚举),
“包含”,
新[]{typeof(int)},
listParameter,
itemParameterProperty);
var delegateTypeExpression=Expression.GetFuncType(新[]{query.ElementType,typeof(bool)});
var whereExpression=Expression.Lambda(
授权类型表达式,
包含压力,
新[]{itemParameter}
);
表达式callWhere=Expression.Call(
类型(可查询),
“哪里”,
新类型[]{query.ElementType},//Where()的类型args
query.Expression,
何处表达
);
返回query.Provider.CreateQuery(callWhere);
}
}
我假设您的属性将提供一些允许值数组
以下是一些有助于此过程的扩展方法:
public static class TypeExtensions
{
public static TAttribute GetAttribute<TAttribute>(this Type type)
{
var attributes = type.GetCustomAttributes(typeof(TAttribute), true);
if (attributes.Length == 0) return default(TAttribute);
return (TAttribute)attributes[0];
}
public static PropertyInfo GetPropertyWithAttributeValue<TAttribute>(
this IEnumerable<PropertyInfo> properties,
Func<TAttribute, bool> findPredicate)
where TAttribute : Attribute
{
var property = from p in properties
where p.HasAttribute<TAttribute>() &&
findPredicate.Invoke(p.GetAttribute<TAttribute>())
select p;
return property.FirstOrDefault();
}
public static bool HasAttribute<TAttribute>(this PropertyInfo propertyInfo)
{
return propertyInfo.GetCustomAttributes(typeof(TAttribute), true).Any();
}
public static TAttribute GetAttribute<TAttribute>(this PropertyInfo propertyInfo)
{
var attributes = propertyInfo.GetCustomAttributes(typeof(TAttribute), true);
if (attributes.Length == 0) return default(TAttribute);
return (TAttribute)attributes[0];
}
}
公共静态类类型扩展
{
公共静态TatAttribute GetAttribute(此类型)
{
var attributes=type.GetCustomAttributes(typeof(tatAttribute),true);
if(attributes.Length==0)返回默认值(tatAttribute);
返回(TatAttribute)属性[0];
}
公共静态属性信息GetPropertyWithAttributeValue(
这是一个可数属性,
Func findPredicate)
其中:属性
{
var property=从属性中的p开始
其中p.HasAttribute()&&
findPredicate.Invoke(p.GetAttribute())
选择p;
返回属性。FirstOrDefault();
}
公共静态bool HasAttribute(此PropertyInfo PropertyInfo)
{
返回propertyInfo.GetCustomAttributes(typeof(tatAttribute),true).Any();
}
公共静态TatAttribute GetAttribute(此PropertyInfo PropertyInfo)
{
var attributes=propertyInfo.GetCustomAttributes(typeof(tatAttribute),true);
if(attributes.Length==0)返回默认值(tatAttribute);
返回(TatAttribute)属性[0];
}
}
我自己还没有试过运行它,但希望它足以让您开始。您可以尝试在运行时创建动态表达式。您不必显式地将IQueryable转换回它的泛型类型,只要y
public static class TypeExtensions
{
public static TAttribute GetAttribute<TAttribute>(this Type type)
{
var attributes = type.GetCustomAttributes(typeof(TAttribute), true);
if (attributes.Length == 0) return default(TAttribute);
return (TAttribute)attributes[0];
}
public static PropertyInfo GetPropertyWithAttributeValue<TAttribute>(
this IEnumerable<PropertyInfo> properties,
Func<TAttribute, bool> findPredicate)
where TAttribute : Attribute
{
var property = from p in properties
where p.HasAttribute<TAttribute>() &&
findPredicate.Invoke(p.GetAttribute<TAttribute>())
select p;
return property.FirstOrDefault();
}
public static bool HasAttribute<TAttribute>(this PropertyInfo propertyInfo)
{
return propertyInfo.GetCustomAttributes(typeof(TAttribute), true).Any();
}
public static TAttribute GetAttribute<TAttribute>(this PropertyInfo propertyInfo)
{
var attributes = propertyInfo.GetCustomAttributes(typeof(TAttribute), true);
if (attributes.Length == 0) return default(TAttribute);
return (TAttribute)attributes[0];
}
}