向 Scrutor 注册开放通用装饰器

Mag*_*eus 4 c# dependency-injection decorator scrutor

我有一个标准的 .Net core Api,想要使用 Open Generic IRepository 并用 DomainEventPublisher 装饰它,以便在持久化后将事件推送到 servicsBus。然而,我很早就使用过 Simple Injector,我是它的忠实粉丝。但现在使用 MediatR 时,我尝试仅使用 .net Core DI 和 Scrutor 包进行装饰来简化 DI。

问题是我收到的错误:“提供的泛型参数数量不等于泛型类型定义的数量。” 尝试在 Startup 中注册装饰器时来自 Scrutor(下面第二行)。

services.AddSingleton(typeof(IRepository<>), typeof(Repository<>));
services.Decorate(typeof(IRepository<>), typeof(DomainEventPublisher<>));
Run Code Online (Sandbox Code Playgroud)

我已经关闭了这些通用类/接口,然后它就可以工作了。但我不擅长这个。我会像以前在 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));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ven 5

不可能将装饰器应用于 Scrutor 的开放通用注册。Scrutor 论坛对此进行了讨论。这是由于底层 Microsoft DI 容器的限制造成的。这是 Scrutor 无法规避的限制。

相反,请切换到支持此功能的成熟 DI 容器之一。