向 Scrutor 注册 Open Generic Decorator
Register Open Generic Decorator with Scrutor
我有一个标准的 .Net 核心 Api,我想使用一个 Open Generic IReposistory 并用 DomainEventPublisher 装饰它,以便在持久化后将事件推送到 servicsBus。
但是,我很早就使用了 Simple Injector,我非常喜欢它。但是现在,当我使用 MediatR 时,我试图通过仅使用 .net Core DI 和 Scrutor 包进行装饰来简化 DI。
问题是我得到的一个错误:
“提供的泛型参数的数量不等于泛型类型定义的数量。”尝试在 Startup 中注册装饰器时来自 Scrutor(下面第二行)。
services.AddSingleton(typeof(IRepository<>), typeof(Repository<>));
services.Decorate(typeof(IRepository<>), typeof(DomainEventPublisher<>));
我关闭了这些通用的 classes/interfaces 然后它就可以工作了。但我对此并不擅长。我会像以前在 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 的开放通用注册。这在 Scrutor 论坛上进行了讨论 here。这是由于底层 Microsoft DI 容器的限制。这是 Scrutor 无法绕过的限制。
相反,切换到支持此功能的成熟 DI 容器之一。
我有一个标准的 .Net 核心 Api,我想使用一个 Open Generic IReposistory 并用 DomainEventPublisher 装饰它,以便在持久化后将事件推送到 servicsBus。 但是,我很早就使用了 Simple Injector,我非常喜欢它。但是现在,当我使用 MediatR 时,我试图通过仅使用 .net Core DI 和 Scrutor 包进行装饰来简化 DI。
问题是我得到的一个错误: “提供的泛型参数的数量不等于泛型类型定义的数量。”尝试在 Startup 中注册装饰器时来自 Scrutor(下面第二行)。
services.AddSingleton(typeof(IRepository<>), typeof(Repository<>));
services.Decorate(typeof(IRepository<>), typeof(DomainEventPublisher<>));
我关闭了这些通用的 classes/interfaces 然后它就可以工作了。但我对此并不擅长。我会像以前在 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 的开放通用注册。这在 Scrutor 论坛上进行了讨论 here。这是由于底层 Microsoft DI 容器的限制。这是 Scrutor 无法绕过的限制。
相反,切换到支持此功能的成熟 DI 容器之一。