Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 创建IQueryable的通用过滤器<;T>;其中筛选器使用在接口中定义的属性_C#_Linq_Generics_Multi Tenant_Iqueryable - Fatal编程技术网

C# 创建IQueryable的通用过滤器<;T>;其中筛选器使用在接口中定义的属性

C# 创建IQueryable的通用过滤器<;T>;其中筛选器使用在接口中定义的属性,c#,linq,generics,multi-tenant,iqueryable,C#,Linq,Generics,Multi Tenant,Iqueryable,我正在为多租户web API实现一个自定义处理管道。这就要求数据检索管道的最后一步必须确保只将特定于给定租户的数据返回给调用者,我认为最好使用 对于数据检索,过程如下所示: HTTP调用命中瘦控制器,在瘦控制器中解析为符合CQS的查询,并传递给中介进行处理 中介器被配置为通过管道提供所有请求,这有几个步骤 验证 缓存 任何查询特定的预处理程序 在处理程序中处理查询(返回IQueryable) 任何查询特定的后期处理程序 返回调用者(返回IQueryable) 我的域模型有一组类,它们继承自

我正在为多租户web API实现一个自定义处理管道。这就要求数据检索管道的最后一步必须确保只将特定于给定租户的数据返回给调用者,我认为最好使用

对于数据检索,过程如下所示:

  • HTTP调用命中瘦控制器,在瘦控制器中解析为符合CQS的查询,并传递给中介进行处理
  • 中介器被配置为通过管道提供所有请求,这有几个步骤

  • 验证
  • 缓存
  • 任何查询特定的预处理程序
  • 在处理程序中处理查询(返回
    IQueryable
  • 任何查询特定的后期处理程序
  • 返回调用者(返回
    IQueryable
我的域模型有一组类,它们继承自一个基类,该基类由一个简单的imultitantity接口修饰

公共接口不可扩展性
{
长租户{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
,这导致了LINQ
Where()的结果
属于
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);
    }
}