向 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 容器之一。