使用筛包装进行分页时出现问题



我正在构建小型WebApi(使用CQRS和MediatR(作为我在IT领域的第一份工作的投资组合,我在使用Sieve.net对结果进行筛选、排序和分页时遇到了一些问题。现在我对分页有问题。

我想接收这样的数据:

{
"currentPage": 1,
"pageSize": 5,
"pageCount": 1,
"rowCount ": 5,
"data": [
{
"id": 1,
"name": "name",
"description": "description,
}
]
}  

我创建了一个基类:

public abstract class PagedRequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
public abstract Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken);
}

PagedResponseExtension:

public static class PagedResponseExtension
{
public static async Task<PagedResponse<TResponse>> ToPagedAsync<TEntity, TResponse>
(this IQueryable<TEntity> query, IMapper mapper, ISieveProcessor sieve, SieveModel model = null,
CancellationToken cancellationToken = default) where TResponse : ResponseBase<TResponse>
{
var page = model?.Page ?? 1;
var pageSize = model?.PageSize ?? 50;
if (model != null)
query = sieve.Apply(model, query, applyPagination: false);
var rowCount = await query.CountAsync(cancellationToken);
var pageCount = (int)Math.Ceiling((double)rowCount / pageSize);
var skip = (page - 1) * pageSize;
var pagedQuery = query.Skip(skip).Take(pageSize);
var response = new PagedResponse<TResponse>
{
CurrentPage = page,
PageSize = pageSize,
PageCount = pageCount,
RowCount = rowCount
};
response.Results = await pagedQuery.ProjectTo<TResponse>(mapper.ConfigurationProvider)
.ToListAsync(cancellationToken);
return response;
}
}

PagedResponse:

public class PagedResponse<TResponse> where TResponse : class
{
public int CurrentPage { get; set; }
public int PageSize { get; set; }
public int PageCount { get; set; }
public long RowCount { get; set; }
public IList<TResponse> Results { get; set; } = new List<TResponse>();
public ErrorModel Error { get; internal set; }
}

GetProductsQuery:

public class GetProductsQuery : QueryBaseWithSieve<List<Product>>
{
public SieveModel SieveModel { get; init; }
public async override Task<List<Product>> Execute(FlowerShopStorageContext context, ISieveProcessor sieveProcessor)
{
var query = sieveProcessor.Apply(SieveModel, context.Products.AsNoTracking());

return await query.ToListAsync();
}
}

这是我当前的QueryHandler:

public class GetProductsHandler : IRequestHandler<GetProductsRequest, GetProductsResponse>
{
private readonly IMapper mapper;
private readonly IQueryExecutor queryExecutor;
public GetProductsHandler(IMapper mapper, IQueryExecutor queryExecutor)
{
this.mapper = mapper;
this.queryExecutor = queryExecutor;
}
public async Task<GetProductsResponse> Handle(GetProductsRequest request, CancellationToken cancellationToken)
{
var query = new GetProductsQuery()
{
SieveModel = request.SieveModel
};
var products = await this.queryExecutor.ExecuteWithSieve(query);
if (products == null)
{
return new GetProductsResponse()
{
Error = new ErrorModel(ErrorType.NotFound)
};
}
var mappedProducts = this.mapper.Map<List<Domain.Models.ProductDTO>>(products);
var response = new GetProductsResponse()
{
Data = mappedProducts
};
return response;
}
}

这就是我试图解决的方法:

public class GetProductsHandler : PagedRequestHandler<GetProductsRequest, PagedResponse<GetProductsResponse>>
{
private readonly IMapper mapper;
private readonly IQueryExecutor queryExecutor;
private readonly SieveProcessor sieveProcessor;
public GetProductsHandler(IMapper mapper, IQueryExecutor queryExecutor, SieveProcessor sieveProcessor)
{
this.mapper = mapper;
this.queryExecutor = queryExecutor;
this.sieveProcessor = sieveProcessor;
}
public override async Task<PagedResponse<GetProductsResponse>> Handle(GetProductsRequest request, CancellationToken cancellationToken)
{
var query = new GetProductsQuery()
{
SieveModel = request.SieveModel
};
var products = await this.queryExecutor.ExecuteWithSieve(query);
if (products == null)
{
return new PagedResponse<GetProductsResponse>()
{
Error = new ErrorModel(ErrorType.NotFound)
};
}
products.AsQueryable();
// var mappedProducts = this.mapper.Map<List<Domain.Models.ProductDTO>>(products);

var response = new PagedResponse<GetProductsResponse>()
{
//Results = products
// Data = mappedProducts
//Results = (IList<GetProductsResponse>)products  //mappedProducts   
//products.ToList()
};
// Error    CS1929  'PagedResponse<GetProductsResponse>' does not contain a definition for 'ToPagedAsync' and the best extension method overload 
// 'PagedResponseExtension.ToPagedAsync<GetProductsRequest, GetProductsResponse>(IQueryable<GetProductsRequest>, IMapper, ISieveProcessor, SieveModel, CancellationToken)' 
// requires a receiver of type 'IQueryable<GetProductsRequest>' Shop.ApplicationServices    C:...Shop.ApplicationServicesAPIHandlersProductGetProductsHandler.cs

return await response.ToPagedAsync<GetProductsRequest, GetProductsResponse>(query, mapper, sieveProcessor, request.SieveModel);  
//return response.ToPagedAsync<GetProductsRequest, GetProductsResponse>();         
}
}

同样在ProductsController中,我得到了这个问题:

类型"Shop.ApplicationServices.Lneneneba API.Domain.Product.GetProductsRequest"不能用作泛型类型或方法中的类型参数"TRequest"'ApiControllerBase.HandleRequest<TRequest、TResponse>(请求('。没有来自的隐式引用转换'Shop.ApplicationServices.neneneba API.Domain.Product.GetProductsRequest'到'MediatR.IRequest<Shop.ApplicationServices.Lneneneba API.Domain.Product.GetProductsResponse>'。店铺C:。。。\商店\控制器\产品控制器.cs

[HttpGet]
[Route("")]
public async Task<IActionResult> GetAllProducts([FromQuery] SieveModel sieveModel)
{            
GetProductsRequest request = new GetProductsRequest { SieveModel = sieveModel };
return await this.HandleRequest<GetProductsRequest, GetProductsResponse>(request);
}  

我是否试图正确地解决整个问题?

提前谢谢!

谨致问候,卢卡斯

我回答自己的问题,以显示我在代码中的更改(但现在出现异常(:

public abstract class PagedRequestHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
public abstract Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken);
}

PagedResponseExtension:

public static class PagedResponseExtension
{
public static async Task<PagedResponse<TEntity>> ToPagedAsync<TResponse, TEntity> (this IQueryable<TEntity> query, IMapper mapper, ISieveProcessor sieve, SieveModel model = null,
CancellationToken cancellationToken = default) where TResponse : class        
{
var page = model?.Page ?? 1;
var pageSize = model?.PageSize ?? 50;
if (model != null)
query = sieve.Apply(model, query, applyPagination: false);
var rowCount = await query.CountAsync(cancellationToken);
var pageCount = (int)Math.Ceiling((double)rowCount / pageSize);
var skip = (page - 1) * pageSize;
var pagedQuery = query.Skip(skip).Take(pageSize);
var response = new PagedResponse<TEntity>
{
CurrentPage = page,
PageSize = pageSize,
PageCount = pageCount,
RowCount = rowCount               
};
response.Results = await pagedQuery.ProjectTo<TEntity>(mapper.ConfigurationProvider).ToListAsync(cancellationToken);;
return response;
}
}

PagedResponse:

public class PagedResponse<TResponse> where TResponse : class
{
public int CurrentPage { get; set; }
public int PageSize { get; set; }
public int PageCount { get; set; }
public long RowCount { get; set; }
// public IList<TResponse> Results { get; set; } = new List<TResponse>();
public List<TResponse> Results { get; set; } = new();
}

GetProductsQuery:

public class GetProductsQuery : QueryBaseWithSieve<IQueryable<Entities.Product>>
//public class GetProductsQuery : QueryBaseWithSieve<List<Product>>
{
public SieveModel SieveModel { get; init; }
public async override Task<IQueryable<Entities.Product>> Execute(FlowerShopStorageContext context, ISieveProcessor sieveProcessor)
// public async override Task<List<Product>> Execute(FlowerShopStorageContext context, ISieveProcessor sieveProcessor)
{
var query = sieveProcessor.Apply(SieveModel, context.Products.AsNoTracking());

return await Task.FromResult(query);   
// return await query.ToListAsync();
}
}

我就是这样解决的:

//public class GetProductsHandler : IRequestHandler<GetProductsRequest, GetProductsResponse>
public class GetProductsHandler : PagedRequestHandler<GetProductsRequest, GetProductsResponse>
{
private readonly IMapper mapper;
private readonly IQueryExecutor queryExecutor;
// Here in place of implementation I need to use interface
// private readonly SieveProcessor sieveProcessor;
private readonly ISieveProcessor sieveProcessor;

public GetProductsHandler(IMapper mapper, IQueryExecutor queryExecutor, ISieveProcessor sieveProcessor)
{
this.mapper = mapper;
this.queryExecutor = queryExecutor;
this.sieveProcessor = sieveProcessor;
}
public override async Task<GetProductsResponse> Handle(GetProductsRequest request, CancellationToken cancellationToken)
//public override async Task<PagedResponse<GetProductsResponse>> Handle(GetProductsRequest request, CancellationToken cancellationToken)
{
var query = new GetProductsQuery()
{
SieveModel = request.SieveModel
};
var products = await this.queryExecutor.ExecuteWithSieve(query);
if (products is null)
{
return new GetProductsResponse()
{
Error = new ErrorModel(ErrorType.NotFound)
};
}
var mappedProducts = this.mapper.Map<IQueryable<ProductDTO>>(products);
var results = await mappedProducts.ToPagedAsync<GetProductsResponse, ProductDTO>(mapper, sieveProcessor);
//var results  = await mappedProducts.ToPagedAsync<ProductDTO, GetProductsResponse>(mapper, sieveProcessor);
var response = new GetProductsResponse() { Data = results };
return response;
}
}

我现在没有问题,但无法建立一个项目。但有一些例外,取决于在Startup.cs:中的注册

  • System.AggregateException:'无法构造某些服务(验证服务描述符'ServiceType:MediatR.IRequestHandler`2[FlowerShop.ApplicationServices.Lneneneba API.Domain.Product.GetProductsRequest,FlowerShop.AApplicationServices.OperAPI.Directory.Product.Get-ProductsResponse]时出错]生存时间:瞬态实现类型:FlowerShop.ApplicationServices.Lneneneba API.Handlers.Product.GetProductsHandler":在尝试激活"FlowerShop.ApplicationServices.SiveProcessor"时,无法解析类型为"Sieve.Services.SeeveProcessor"的服务。(">
  • InvalidOperationException:尝试激活"FlowerShop.ApplicationServices.Lneneneba API.Handlers.Product.GetProductsHandler"时,无法解析类型为"Sieve.Services.SiveProcessor"的服务

或:

  • System.ArgumentException:"无法实例化实现类型"FlowerShop.ApplicationServices.API.HHandlers.PagedRequestHandler2[FlowerShop.ApplicationServices.API.Domain.Product.GetProductsRequest,FlowerShop.ApplicationServices.API.Domain.Product.GetProductsResponse]' for service type 'MediatR.IRequestHandler2[FlowerShop.AApplicationServices.Lneneneba API.Domain.Product.GetProductsRequest,FlowerShop.ApplicationServices.OperAPI.Directory.Product.Get-ProductsResponse]"。">

这是我的Startup.cs

public void ConfigureServices(IServiceCollection services)
{  
// Here I changend the way of registration
// services.AddScoped<ISieveProcessor, ApplicationSieveProcessor>();
services.AddScoped<ISieveProcessor, SieveProcessor>();
}

编辑:
我解决了这个问题,但得到了另一个带有映射的问题,但我将在新问题中对此进行说明。

最新更新