car*_*rio 4 c# .net-core asp.net-core asp.net-core-webapi
我有以下场景:
我想创建一个自定义结果过滤器,允许我使用ResultFilterAttribute类的子类向响应添加分页标题。为了创建标题中使用的分页元数据,我创建了一个分页助手服务,该服务被注入到控制器类中,并且需要一个 PagingModel 对象来生成元数据。
要将分页元数据添加到过滤器中的响应,我需要访问 pagingMetadata 和我想从控制器返回的实际值(实体、dto 或其他任何值)。为了能够将两个对象传递给结果过滤器,我使用了一个元组。
问题是我想让这个过滤器有点通用,我试图将来自控制器的实际值(实体,dto ...)转换为一个对象,这给我抛出一个异常,说转换不是可能的。
我该如何进行选角?或者我应该使用不同的方法吗?
我尝试直接在结果过滤器中使用 paginationHelperService 而不是在控制器中使用它,但是不可能从控制器传递服务的实例,因为属性类不允许它。
我也尝试使用泛型,我认为这是实现转换的最简单方法。如果我可以使属性通用,我可以将对象转换为其实际类型,但不幸的是,这是不可能的,因为它是一个属性类。
// Controller
[HttpGet]
[AddPaginationHeader]
public async Task<IActionResult> Get([FromQuery]PagingModel pagingModel,
[FromHeader(Name = "Accept")]string mediaType) {
var pagedCollection = repository.GetPage(pagingModel);
PaginationMetadata paginationMetadata = paginationHelperService.GetPagingMetadata(pagingModel);
if (mediaType == "mycustommediatype") {
var shapedCollection = ShapeCollectionOfData(pagedCollection);
return Ok((shapedCollection, pagingModel));
} else {
return Ok((pagedCollection, pagingModel));
}
}
// Custom Result Filter
public override void OnResultExecuting(ResultExecutingContext context) {
var result = context.Result as ObjectResult;
if (result?.Value != null && result?.StatusCode >= 200 &&
result?.StatusCode < 300) {
(object value, PaginationMetadata paginationMetadata) = ((object, PaginationMetadata))result.Value; // Casting
string paginationMetadataString = (context.HttpContext.Request.Headers["Accept"] == "mycustommediatype")
? JsonConvert.SerializeObject(paginationMetadata.FullMetadata)
: JsonConvert.SerializeObject(pagingMetadata.GenericMetadata);
context.HttpContext.Response.Headers.Add("X-Pagination", paging);
context.Result.Value = value;
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试直接在结果过滤器中使用 paginationHelperService 而不是在控制器中使用它,但是不可能从控制器传递服务的实例,因为属性类不允许它。
虽然您不能将服务注入到 中Attribute,但您可以使用 的属性ServiceFilter(typeof(Your_Filter_Type))来启用任何过滤器,以便您可以根据需要注入服务。
例如,创建一个AddPaginationHeader结果过滤器(不是Attribute):
public class AddPaginationHeader : IResultFilter
{
private readonly IRepository repository;
// inject services
public AddPaginationHeader(IRepository repository, ... other services)
{
this.repository = repository;
}
public void IResultFilter.OnResultExecuting(ResultExecutingContext context)
{
...
}
public void IResultFilter.OnResultExecuted(ResultExecutedContext context) { ... }
}
Run Code Online (Sandbox Code Playgroud)
并且不要忘记在 Startup.cs 中注册此服务:
services.AddScoped<AddPaginationHeader>();
Run Code Online (Sandbox Code Playgroud)
最后,您可以通过[ServiceFilterAttribute]以下方式启用此过滤器:
[HttpGet]
[ServiceFilter(typeof(AddPaginationHeader))]
public async Task Get([FromQuery]PagingModel pagingModel, [FromHeader(Name = "Accept")]string mediaType)
{
....
}
我也尝试使用泛型,我认为这是实现转换的最简单方法。如果我可以使属性通用,我可以将对象转换为它的实际类型,但不幸的是这是不可能的,因为它是一个属性类。
同样的技巧也可以用于泛型类型。例如,将上述AddPaginationHeader过滤器更改为class AddPaginationHeader<TResult> : IResultFilter,您可以通过以下方式启用此过滤器:
[ServiceFilter(typeof(AddPaginationHeader<(object,PaginationMetadata)>))]
Run Code Online (Sandbox Code Playgroud)
您可以TResult根据需要扩展泛型。唯一的技巧是添加过滤器ServiceFilter。
| 归档时间: |
|
| 查看次数: |
642 次 |
| 最近记录: |