问题描述
我有一个标准的.Net核心Api,并且希望使用Open Generic IReposistory,并使用DomainEventPublisher对其进行修饰,以便在持久化后将事件推送到servicsBus。 但是,我很早以前就使用过Simple Injector,我对此非常感兴趣。但是现在,当使用MediatR Im时,我试图通过仅使用.net Core DI和scrutor软件包进行装饰来简化DI。
问题是我得到的错误: “提供的泛型参数的数量不等于泛型类型定义的复杂性。”尝试在“启动”中注册装饰器时从scrutor中访问(以下第二行)。
services.AddSingleton(typeof(IRepository<>),typeof(Repository<>));
services.Decorate(typeof(IRepository<>),typeof(DomainEventPublisher<>));
我已经关闭了这些通用的类/接口,然后它起作用了。但是我对此不好。我会以正确的方式像以前在Simpleinjector中所做的那样,并注册开放的通用装饰器。
任何建议可能是什么问题?
public class Repository<TEntity> : IRepository<TEntity>
{
private readonly CosmosClient _client;
private readonly IDataContext<TEntity> _context;
private readonly Container _container;
public Repository(CosmosClient client,IDataContext<TEntity> context)
{
_client = client;
_context = context ?? throw new ArgumentNullException(nameof(context));
_container = _client.GetContainer(_context.GetDatabase(),_context.GetContainer());
}
public virtual async Task Add(TEntity entity)
{
try
{
var response = await _container.CreateItemAsync(entity,new PartitionKey(_context.GetPartitionKey(entity)));
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public virtual async Task<TEntity> Get(string id)
{
var response = await _container.ReadItemAsync<TEntity>(id,new PartitionKey(_context.GetPartitionKey(id)));
return response.Resource;
}
public virtual async Task<TEntity> Update(TEntity entity)
{
var response = await _container.UpsertItemAsync(entity,new PartitionKey(_context.GetPartitionKey(entity)));
return response.Resource;
}
public async Task Remove(string id)
{
var response = await _container.DeleteItemAsync<TEntity>(id,new PartitionKey(_context.GetPartitionKey(id)));
}
public class DomainEventPublisher<TEntity> : IRepository<TEntity>
{
private readonly IRepository<TEntity> _decoratedRepository;
private readonly ITopicAdapter _bus;
private readonly IMapper _mapper;
private List<IDomainEvent> _eventsToProcess = new List<IDomainEvent>();
public DomainEventPublisher(IRepository<TEntity> decoratedRepository,ITopicAdapter bus,IMapper mapper)
{
_decoratedRepository = decoratedRepository ?? throw new ArgumentNullException(nameof(decoratedRepository));
_bus = bus ?? throw new ArgumentNullException(nameof(bus));
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
}
public async Task Add(TEntity entity)
{
// Get all domain events raised by source entity
var events = CollectEvents(entity);
await _decoratedRepository.Add(entity);
await HandleEvents(events);
}
public async Task<TEntity> Get(string id)
{
return await _decoratedRepository.Get(id);
}
public async Task<TEntity> Update(TEntity entity)
{
// Get all domain events raised by source entity
var events = CollectEvents(entity);
var result = await _decoratedRepository.Update(entity);
await HandleEvents(events);
return result;
}
public async Task Remove(string id)
{
await _decoratedRepository.Remove(id);
}
private List<IDomainEvent> CollectEvents(TEntity entity)
{
if (entity is IEntity entityWithEvents)
return entityWithEvents.Events;
return new List<IDomainEvent>();
}
private async Task HandleEvents(List<IDomainEvent> events)
{
// if we ended up on this line we kNow that repository persisted changes and Now send events to bus
foreach (var domainEvent in events)
{
await _bus.Send(_mapper.MapTo(domainEvent));
}
}
}
解决方法
不可能将装饰器应用于Scrutor的开放式注册。 here在Scrutor论坛上进行了讨论。这是由于基础Microsoft DI容器的限制。这是Scrutor不能绕过的限制。
相反,请切换到确实支持此功能的成熟的DI容器之一。