Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/286.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# 带有简单注入器的CQR中作为横切关注点的分页_C#_.net_Design Patterns_Pagination_Simple Injector - Fatal编程技术网

C# 带有简单注入器的CQR中作为横切关注点的分页

C# 带有简单注入器的CQR中作为横切关注点的分页,c#,.net,design-patterns,pagination,simple-injector,C#,.net,Design Patterns,Pagination,Simple Injector,在我的应用程序设计中,我尝试将模式作为应用于模式的一部分来实现 我也有一个观点,我认为分页不是业务逻辑的一部分(因此是一个交叉关注点)。这是已经做出的决定,不应在本主题中讨论 在我的设计中,目的是表示层可以使用具有特定封闭泛型类型的分页查询 IQueryHandler<GetAllItemsQuery, PaginatedQuery<Item>> 因此,处理程序的返回类型是IEnumerable。这样,处理程序就被强制执行。 我面临的问题可能是我使用的方式。因为我正在注

在我的应用程序设计中,我尝试将模式作为应用于模式的一部分来实现

我也有一个观点,我认为分页不是业务逻辑的一部分(因此是一个交叉关注点)。这是已经做出的决定,不应在本主题中讨论

在我的设计中,目的是表示层可以使用具有特定封闭泛型类型的分页查询

IQueryHandler<GetAllItemsQuery, PaginatedQuery<Item>>
因此,处理程序的返回类型是
IEnumerable
。这样,处理程序就被强制执行。 我面临的问题可能是我使用的方式。因为我正在注册我的
IQueryHandler
like

container.Register(typeof(IQueryHandler<,>), assemblies);
关于操作是什么以及为什么无效,异常并不十分清楚。也许我做错了什么

以下是拦截器的实现:

public class PaginatedQueryHandlerInterceptor<TQuery, TModel> : IQueryHandler<TQuery, PaginatedResult<TModel>>
    where TQuery : PaginatedQuery<TModel>
{
    private readonly IQueryHandler<TQuery, IEnumerable<TModel>> _queryHandler;

    public PaginatedQueryHandlerInterceptor(IQueryHandler<TQuery, IEnumerable<TModel>> queryHandler)
    {
        _queryHandler = queryHandler;
    }

    public PaginatedResult<TModel> Handle(TQuery query)
    {
        return (dynamic) _queryHandler.Handle(query);
    }
}
公共类分页QueryHandlerInterceptor:IQueryHandler
其中TQuery:PaginatedQuery
{
专用只读IQueryHandler\u queryHandler;
公共分页queryHandler拦截器(IQueryHandler queryHandler)
{
_queryHandler=queryHandler;
}
公共分页结果句柄(TQuery查询)
{
返回(动态)\ u查询句柄(查询);
}
}
还有装饰师:

public class PaginationQueryHandlerDecorator<TQuery, TResult> : IQueryHandler<TQuery, TResult>
        where TQuery : class, IQuery<TResult>
    {
        private readonly IQueryHandler<TQuery, TResult> _decoratee;

        public PaginationQueryHandlerDecorator(
            IQueryHandler<TQuery, TResult> decoratee)
        {
            _decoratee = decoratee;
        }

        public TResult Handle(TQuery query)
        {
            query.ThrowIfNull(nameof(query));

            var result = _decoratee.Handle(query);

            if (query.IsPaginationQuery(out var paginatedQuery))
            {
                return Paginate(result, paginatedQuery.Pagination);
            }

            return result;
        }

        private static TResult Paginate(TResult result, Pagination pagination)
        {
            return Paginate(result as dynamic, pagination.Page, pagination.ItemsPerPage);
        }

        private static PaginatedResult<TModel> Paginate<TModel>(IEnumerable<TModel> result, int page, int itemsPerPage)
        {
            var items = result as TModel[] ?? result.ToArray();

            var paginated = items.Skip(page * itemsPerPage).Take(itemsPerPage).ToArray();

            return new PaginatedResult<TModel>
            {
                Items = paginated,
                Count = items.Length
            };
        }
    }
公共类分页QueryHandlerDecorator:IQueryHandler
提问地点:课堂、课堂
{
私有只读IQueryHandler\u装饰对象;
公共分页查询HandlerDecorator(
IQueryHandler(装饰者)
{
_被装饰者=被装饰者;
}
公共TResult句柄(TQuery查询)
{
query.ThrowIfNull(name of(query));
var result=_decoratee.Handle(查询);
if(query.IsPaginationQuery(out var paginatedQuery))
{
返回Paginate(结果,paginatedQuery.Pagination);
}
返回结果;
}
私有静态TResult分页(TResult result,分页分页)
{
返回分页(结果为dynamic、pagination.Page、pagination.ItemsPerPage);
}
私有静态分页结果分页(IEnumerable result,int page,int itemsPerPage)
{
var items=结果为TModel[]??结果.ToArray();
var paginated=items.Skip(page*itemsPerPage).Take(itemsPerPage.ToArray();
返回新的分页结果
{
项目=分页,
计数=项目。长度
};
}
}
这是已经做出的决定,不应在本主题中讨论

嗯。。。。如果你坚持:)

但至少要防止这些查询返回
IEnumerable
,而是返回
IQueryable
。使用
IEnumerable
将导致从数据库返回所有数据,即使您对其进行翻页

也就是说,我不确定您的代码出了什么问题,但我想建议一种稍微不同的方法:

public class PagedQueryHandler<TQuery, TItem>
    : IQueryHandler<PagedQuery<TQuery, TItem>, Paged<TItem>>
    where TQuery : IQuery<IQueryable<TItem>>
{
    private readonly IQueryHandler<TQuery, IQueryable<TItem>> handler;

    public PagedQueryHandler(IQueryHandler<TQuery, IQueryable<TItem>> handler)
    {
        this.handler = handler;
    }

    public Paged<TItem> Handle(PagedQuery<TQuery, TItem> query)
    {
        var paging = query.PageInfo ?? new PageInfo();
        IQueryable<TItem> items = this.handler.Handle(query.Query);
        return new Paged<TItem>
        {
            Items = items.Skip(paging.PageIndex * paging.PageSize)
                .Take(paging.PageSize).ToArray(),
            Paging = paging,
        };
    }
}
PageInfo
Paged
源自此Github回购协议:

PagedQueryHandler
可以按如下方式注册:

public class Paged<T>
{
    public PageInfo Paging { get; set; }
    public T[] Items { get; set; }
}

public class PageInfo
{
    public int PageIndex { get; set; }
    public int PageSize { get; set; } = 20;
}

public class PagedQuery<TQuery, TItem> : IQuery<Paged<TItem>>
    where TQuery : IQuery<IQueryable<TItem>>
{
    public TQuery Query { get; set; }
    public PageInfo PageInfo { get; set; }
}
container.Register(typeof(IQueryHandler<,>), typeof(PagedQueryHandler<,>));
container.Register(typeof(IQueryHandler),typeof(PagedQueryHandler));
通过此类及其注册,您只需将可分页查询处理程序注入使用者,例如:

public class ItemsController
{
    IQueryHandler<PagedQuery<GetAllItemsQuery, Item>, Paged<Item>> handler;

    public ItemsController(
        IQueryHandler<PagedQuery<GetAllItemsQuery, Item>, Paged<Item>> handler)
    {
        this.handler = handler;
    }

    public ActionResult Index(PagedQuery<GetAllItemsQuery, Item> query)
    {
        return View(this.handler.Handle(query));
    }
}
公共类ItemsController
{
IQueryHandler;
公共项目控制器(
IQueryHandler(处理程序)
{
this.handler=handler;
}
公共操作结果索引(PagedQuery查询)
{
返回视图(this.handler.Handle(查询));
}
}

实际问题确实是我做错了,但与简单的喷油器无关

当使用注册表条件时,在谓词中调用此扩展方法:

bool PaginationInterceptorPredicate(PredicateContext predicateContext) =>
    predicateContext.ServiceType.GetGenericArguments()[0].IsPaginatedQuery();
IsPaginatedQuery
的实现错误,导致异常:

public static bool IsPaginatedQuery(this Type queryType) => 
    queryType.GetInterfaces().Any(i => i.GetGenericTypeDefinition() == typeof(PaginatedQuery<>));
publicstaticboolispaginatedquery(此类型queryType)=>
queryType.GetInterfaces().Any(i=>i.GetGenericTypeDefinition()==typeof(PaginatedQuery));

由于查询还实现了非泛型接口
IPagination
,因此
GetGenericTypeDefinition()
方法导致了异常。

您的解决方案存在一个小问题。也就是说,当
PagedQueryHandler
调用
.ToArray()
时,我的
DbContext
被释放。因为我正在用
LifetimeScopeQueryHandlerProxy
装饰我的查询处理程序。这意味着您不应该装饰返回
IQueryable
实例的查询处理程序。或者确保LifetimeScopeQueryHandlerProxy检测它是否嵌套,并防止它启动和处理DbContext。但这并不是我的设计的真正问题,因为你的原始帖子也包含同样的问题。我已经将我的初始设计重构为你的略有不同的方法,现在效果非常好。我在原始设计中使用
IEnumerable
的原因是,我的查询将继承自
PaginatedQuery
,强制处理程序返回
IEnumerable
,但让业务部门决定它是否是隐藏在引擎盖下的
IQueryable
(可能底层数据模型的性能非常出色)。在您的设计中,查询仍然是自然的,并且泛型类型约束强制处理程序返回
IQueryable
。缺点是处理程序只能返回查询。TBH我个人坚持让查询处理程序直接返回页面结果,而不使用应用分页的中间映射。如你可以看到,它增加的噪音是最小的,在我看来是合理的。
container.Register(typeof(IQueryHandler<,>), typeof(PagedQueryHandler<,>));
public class ItemsController
{
    IQueryHandler<PagedQuery<GetAllItemsQuery, Item>, Paged<Item>> handler;

    public ItemsController(
        IQueryHandler<PagedQuery<GetAllItemsQuery, Item>, Paged<Item>> handler)
    {
        this.handler = handler;
    }

    public ActionResult Index(PagedQuery<GetAllItemsQuery, Item> query)
    {
        return View(this.handler.Handle(query));
    }
}
bool PaginationInterceptorPredicate(PredicateContext predicateContext) =>
    predicateContext.ServiceType.GetGenericArguments()[0].IsPaginatedQuery();
public static bool IsPaginatedQuery(this Type queryType) => 
    queryType.GetInterfaces().Any(i => i.GetGenericTypeDefinition() == typeof(PaginatedQuery<>));