C# 使用Unity拦截的Linq到SQL

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

我在存储库模式中使用带有Unity的LINQtoSQL。我试图在存储库方法
[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];
    }
}