C# 创建IQueryable的通用过滤器<;T>;其中筛选器使用在接口中定义的属性
我正在为多租户web API实现一个自定义处理管道。这就要求数据检索管道的最后一步必须确保只将特定于给定租户的数据返回给调用者,我认为最好使用 对于数据检索,过程如下所示:C# 创建IQueryable的通用过滤器<;T>;其中筛选器使用在接口中定义的属性,c#,linq,generics,multi-tenant,iqueryable,C#,Linq,Generics,Multi Tenant,Iqueryable,我正在为多租户web API实现一个自定义处理管道。这就要求数据检索管道的最后一步必须确保只将特定于给定租户的数据返回给调用者,我认为最好使用 对于数据检索,过程如下所示: HTTP调用命中瘦控制器,在瘦控制器中解析为符合CQS的查询,并传递给中介进行处理 中介器被配置为通过管道提供所有请求,这有几个步骤 验证 缓存 任何查询特定的预处理程序 在处理程序中处理查询(返回IQueryable) 任何查询特定的后期处理程序 返回调用者(返回IQueryable) 我的域模型有一组类,它们继承自
- HTTP调用命中瘦控制器,在瘦控制器中解析为符合CQS的查询,并传递给中介进行处理
- 中介器被配置为通过管道提供所有请求,这有几个步骤
- 验证
- 缓存
- 任何查询特定的预处理程序
- 在处理程序中处理查询(返回
)IQueryable
- 任何查询特定的后期处理程序
- 返回调用者(返回
)IQueryable
公共接口不可扩展性
{
长租户{get;set;}
}
我的想法是注入另一个Post处理程序,特定于返回IQueryable
的所有管道请求,其中TEntity
实现imultitantity
接口。很简单,由于铸造/类型问题,我无法使其工作。我确信我的思想被困在一个无限的愚蠢想法的循环中,我需要有人帮我摆脱这个循环,非常感谢:)
这是我现在的帖子处理程序:
公共接口IAsyncQueryablePostRequestHandler
{
任务句柄(参考响应);
}
公共类PostTenantQueryableFilterHandler:IAsyncQueryablePostRequestHandler
响应:IQueryable
{
公共任务句柄(ref T响应)
{
response=(treresponse)response.Where(t=>t.TenantId==1);
返回任务.FromResult(1);
}
}
现在想象一下,a请求通过管道发出,查询处理程序返回IQueryable。毫不奇怪,一旦我们点击上述处理程序,就会出现异常:
无法强制转换类型为的对象
“System.Data.Entity.Infrastructure.DbQuery'1[imultimatententy]
”
打字
“System.Linq.IQueryable'1[游戏]
”
如果我们调试PostTenantQueryableFilterHandler.Handle()
方法,我们可以看到TreResponse是IQueryable
,但是为了能够包含Where(t=>t.TenantId==1)
部分,我添加了Where-TreResponse:IQueryable
,这导致了LINQWhere()的结果
属于IQueryable
类型,它比IQueryable
更通用,因此不可能从IQueryable
转换为IQueryable
。。。这就是我陷入无限思维循环的地方
救命!:)
编辑:
我能够通过以下方式连接管道:
公共类PostTenantQueryableFilterHandler:IAsyncQueryablePostRequestHandler
响应:IQueryable
在何处,持久性:不持久性
这使得
var intermediate=response.Where(t=>t.TenantId==1.Cast();
但这还不够,对吧
response=(响应)中介;
我变老了
无法强制转换类型为的对象
“System.Data.Entity.Infrastructure.DbQuery'1[imultimatententy]
”
打字
“System.Linq.IQueryable'1[游戏]
”
我应该怎么做才能使treponse
类型不被缩小到IQueryable
,但我仍然能够添加缺少的WHERE谓词
编辑2:
因此,这里真正的限制是调用方法存在于类中,而类不知道作为单独类型的tenty
当我说,a请求通过管道到达,查询处理程序返回IQueryable时,它不够详细。问题是,管道能够处理可以有任何返回类型的查询处理程序,而不仅仅是IQueryable
。所以管道知道的是请求的类型(通过它反馈的查询)和对已处理请求的响应类型。因此,当我在管道中连接PostTenantQueryableFilterHandler
时,tenty
始终是imulttenantity
,这又回到了原点-PostTenantQueryableFilterHandler
不知道tenty
的具体类型,管道无法提供它
我们知道的是一种具体类型的treponse
,它实现了'IQueryable'
长话短说,我仍然在寻找一种方法,将.Where(t=>t.TenantId==1)
过滤器添加到响应中。有什么想法吗
编辑3:
为了使一切都非常清晰,我认为提供一点关于如何调用PostTenantQueryableFilterHandler
的背景知识会有好处
如前所述,所有请求都通过公共处理管道进行反馈(可以使用单独的异步na-sync实现)。管道类签名如下所示:
public class AsyncMediatorPipeline<TRequest, TResponse>
: IAsyncRequestHandler<TRequest, TResponse>
where TRequest : IAsyncRequest<TResponse>
我有两个单独的“post”处理程序,因为通用的“post”处理程序不允许操纵响应
public interface IAsyncPostRequestHandler<in TRequest, in TResponse>
{
Task Handle(TRequest request, TResponse response);
}
公共接口IAsyncPostRequestHandler
{
任务句柄(TRequest请求、TreResponse响应);
}
而可质问的人则是
public interface IAsyncQueryablePostRequestHandler<TResponse, in TEntity>
{
Task Handle(ref TResponse response);
}
公共接口IAsyncQueryablePostRequestHandler
{
任务句柄(参考响应);
}
希望这能让我们对这个问题有更多的了解。这个答案提供了一个有用的信息,以及这不起作用的原因: 基本上
public interface IAsyncPostRequestHandler<in TRequest, in TResponse>
{
Task Handle(TRequest request, TResponse response);
}
public interface IAsyncQueryablePostRequestHandler<TResponse, in TEntity>
{
Task Handle(ref TResponse response);
}
public interface IAsyncQueryablePostRequestHandler<TResponse>
{
Task Handle(ref TResponse response);
}
public class PostTenantQueryableFilterHandler<TResponse> : IAsyncQueryablePostRequestHandler<TResponse>
where TResponse : IQueryable<IMultitenantEntity>
{
public Task Handle(ref TResponse response)
{
var parameter = Expression.Parameter(response.ElementType, "t");
var predicate = Expression.Lambda(
Expression.Equal(
Expression.Property(parameter, "TenantId"),
Expression.Constant(1)),
parameter);
var whereCall = Expression.Call(
typeof(Queryable), "Where", new[] { parameter.Type },
response.Expression, Expression.Quote(predicate));
response = (TResponse)response.Provider.CreateQuery(whereCall);
return Task.FromResult(1);
}
}
public interface IAsyncQueryablePostRequestHandler<TResponse>
{
Task Handle(ref TResponse response);
}
public class PostTenantQueryableFilterHandler<TResponse> : IAsyncQueryablePostRequestHandler<TResponse>
where TResponse : IQueryable<IMultitenantEntity>
{
public Task Handle(ref TResponse response)
{
response = PostTenantQueryableFilter.Handle((dynamic)response);
return Task.FromResult(1);
}
}
static class PostTenantQueryableFilter
{
public static IQueryable<TEntity> Handle<TEntity>(IQueryable<TEntity> response)
where TEntity : class, IMultitenantEntity
{
return response.Where(t => t.TenantId == 1);
}
}