BusinessAction 用于表示用户可以执行的操作。每个操作都与特定实体相关,因此,例如,如果该实体是 Order,则业务操作可以是 CancelOrder、IssueRefund 等。
public abstract class BusinessAction<T>
{
public Guid Id { get; init; }
public Func<T, bool> IsEnabledFor { get; init; }
}
public class CancelOrderAction : BusinessAction<Order>
{
public CancelOrderAction ()
{
Id = Guid.Parse("0e07d05c-6298-4c56-87d7-d2ca339fee1e");
IsEnabledFor = o => o.Status == OrderStatus.Active;
}
}
然后我需要对与特定类型相关的所有操作进行分组。
public interface IActionRegistry
{
Task<IEnumerable<Guid>> GetEnabledActionIdsForAsync(Guid entityId);
}
public class ActionRegistry<T> : IActionRegistry
where T : BaseEntity
{
private readonly IEnumerable<BusinessAction<T>> _actions;
private readonly IRepository<T> _repository;
public ActionRegistry(IEnumerable<BusinessAction<T>> actions, IRepository<T> repository)
{
_actions = actions;
_repository = repository;
}
public async Task<IEnumerable<Guid>> GetEnabledActionIdsForAsync(Guid entityId)
{
var entity = await _repository.FindByIdAsync(entityId);
return entity == null
? Enumerable.Empty<Guid>()
: _actions.Where(a => a.IsEnabledFor(entity)).Select(a => a.Id);
}
}
最后,有一个 API 端点,用于接收实体类型(稍后映射到真实 .NET 类型的一些枚举)和实体 ID。 API端点负责返回为实体的当前状态启用的操作ID。
public class RequestHandler : IRequestHandler<Request, IEnumerable<Guid>>>
{
private readonly Func<Type, IActionRegistry> _registryFactory;
public RequestHandler(Func<Type, IActionRegistry> registryFactory)
{
_registryFactory = registryFactory;
}
public async Task<IEnumerable<Guid>> Handle(Request request, CancellationToken cancellationToken)
{
var type = request.EntityType.GetDotnetType();
var actionRegistry = _registryFactory(type);
var enabledActions = await actionRegistry.GetEnabledActionIdsForAsync(request.EntityId);
return enabledActions;
}
}
问题是:如何在 ASP.NET 中配置依赖注入容器(使用默认选项或 Autofac)以便可以解析 Func ?
对于参数ActionRegistry<T>
我想我可以这样做:
builder.RegisterAssemblyTypes().AsClosedTypesOf(typeof(BusinessAction<>));
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
但是,我该如何配置Func<Type, IActionRegistry>
这样我就能够自动连接一个请求Order
with ActionRegistry<Order>
?有没有办法做到这一点,或者我需要通过编写一些基于类型的 switch 语句来手动配置工厂(以及它看起来如何)?
有没有更好的方法来实现我在这里所需要的?最终目标是,一旦我有了运行时类型,我就可以获得与该类型相关的业务操作列表以及存储库(以便我可以从数据库获取实体)。