上下文:使用AutoMapper 5.1.1的RESTful ASP.NET Core Web API。
我正在尝试实现一种通用方法来在客户端请求时扩展引用的资源。 E.g:
GET /api/Products/4711
返回
{
"id":"4711",
"productName":"flux capacitor",
"category": {
"id": "42",
"obj": null,
}
}
而GET /api/Products/4711?expand=category
应该返回
{
"id":"4711",
"productName":"flux capacitor",
"category": {
"id": "42",
"obj": {
id:"42",
name: "time travelling",
isRestricted: true,
},
}
}
到目前为止,我设法通过
来达到目的public class ExpandableReference<TAggregateRoot,TResource>
{
public int Id { get; set; }
public TResource Obj { get; set; }
}
ITypeConverter
的实现(请注意我的通用存储库的使用,这是成功注入的):public class ReferenceExpander<TAggregateRoot, TResource> : ITypeConverter<int, ExpandableReference<TAggregateRoot, TResource>>
where TAggregateRoot : AggregateRoot
{
private readonly IRepository<TAggregateRoot> repository;
public ReferenceExpander(IRepository<TAggregateRoot> repository)
{
this.repository = repository;
}
public ExpandableReference<TAggregateRoot, TResource> Convert(
int source,
ExpandableReference<TAggregateRoot, TResource> destination,
ResolutionContext context)
{
destination = destination ?? new ExpandableReference<TAggregateRoot, TResource>();
destination.Id = source;
destination.Obj = ExpandReference(source, context);
return destination;
}
private TResource ExpandReference(int source, ResolutionContext context)
{
TAggregateRoot aggregateRoot = repository.SingleOrDefault(source);
TResource resource = context.Mapper.Map<TResource>(aggregateRoot);
return resource;
}
}
CreateMap(typeof(int), typeof(ExpandableReference<,>)).ConvertUsing(typeof(ReferenceExpander<,>));
ForAllPropertyMaps(
map => map.SourceType == typeof(int) && map.DestinationPropertyType.GetGenericTypeDefinition() == typeof(ExpandableReference<,>),
(map, expression) => expression.Condition((agg, res, _, __, ctx) => ctx.ShouldExpand(map.DestinationProperty.Name)));
其中ctx.ShoudExpand(string)
检查ctx的Items字典是否包含目标属性名称。当涉及从我的域对象到资源的映射时,控制器负责添加它。
GET /api/Products/4711
返回
{
"id":"4711",
"productName":"flux capacitor",
"category": null // what?!?!
}
使用category = null
因为条件说在映射期间应该省略它。我需要的是一种这样的后备:
ForAllPropertyMaps(
map => map.SourceType == typeof(int?) && map.DestinationPropertyType.GetGenericTypeDefinition() == typeof(OptionalExpandableReference<,>),
(map, expression) => expression
.Condition((agg, res, _, __, ctx) => ctx.ShouldExpand(map.DestinationProperty.Name))
.Fallback(/*tell AutoMapper to just map the id, omit the obj*/));
IMapSelectionStrategy
以及对MappingContext的访问权限,那将是一个聪明的解决方案。IValueResolver
代替ITypeConverter
使用开放式泛型减少配置的好方法顺便说一下:expression.Condition((agg, res, ???, ???, ctx)
的第三个和第四个参数中出现了什么?我从未见过与null不同的东西。