具有通用接口和组成的简单注入器-不注册接口

Gil*_*rdo 2 .net c# asp.net composition simple-injector

我正在从继承转向合成,如您从此处看到的/sf/ask/2075720741/

现在,我已经完成了所有工作,但是简单的注入器希望我手动注册传入的每种类型的每个接口。这是简化的代码。

我有IBaseEntityService,它由BaseEntityService实现

public interface IEntityBaseService<T> where T : class, IEntityBase
{
    IDataContext Context { get; }

    Task<ICollection<T>> GetAllAsync();

    Task<T> GetAsync(long id);
}

public class EntityBaseService<T> : IEntityBaseService<T>
    where T : class, IEntityBase
{
    protected IDataContext _context;

    public IDataContext Context
    {
        get
        {
            return _context;
        }
    }

    public EntityBaseService(IDataContext context)
    {
        _context = context;
    }

    public async Task<ICollection<T>> GetAllAsync()
    {
        return await _context.Set<T>().ToListAsync();
    }

    public Task<T> GetAsync(long id)
    {
        return _context.Set<T>().Where(e => e.Id == id).FirstOrDefaultAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我有一个IValidationService和ValidationService实现了

public interface IValidationService<T> 
    where T : class, IEntityBase
{
    Task<ValidationResult> ValidateAsync(T entity);

    Task<int> AddAsync(T entity);

    Task<int> UpdateAsync(T entity);
}

public class ValidationService<T> : IValidationService<T>
    where T : class, IEntityBase
{
    private IEntityBaseService<T> _service;
    private IValidator<T> _validator = null;

    public IDataContext Context
    {
        get
        {
            return _service.Context;
        }
    }

    public ValidationService(IEntityBaseService<T> service, IValidator<T> validator)
    {
        _service = service;
        _validator = validator;
    }

    public Task<ValidationResult> ValidateAsync(T entity)
    {
        if (_validator == null) throw new MissingFieldException("Validator does not exist for class " + entity.GetType().ToString() + ". override method if no validation needed");
        return _validator.ValidateAsync(entity);
    }

    public async Task<int> AddAsync(T entity)
    {
        var results = await ValidateAsync(entity);

        if (!results.IsValid)
        {
            throw new ValidationException(results.Errors);
        }

        return await _service.AddAsync(entity);
    }

    public async Task<int> UpdateAsync(T entity)
    {
        var results = await ValidateAsync(entity);

        if (!results.IsValid)
        {
            throw new ValidationException(results.Errors);
        }

        return await _service.UpdateAsync(entity);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我可以使用服务,并传递每个接口。所以我有一个IContentService和ContentService来实现。该服务同时使用IEntityBaseService和IValidationService

public interface IContentService
{
    Task<Content> GetAsync(long id);

    Task<int> AddAsync(Content entity);

    Task<int> UpdateAsync(Content entity);
}

public class ContentService : IContentService
{
    private IEntityBaseService<Content> _service;
    private IValidationService<Content> _validation;

    public ContentService(IEntityBaseService<Content> service, IValidationService<Content> validation)
    {
        _service = service;
        _validation = validation;
    }

    public async Task<Content> GetAsync(long id)
    {
        var content = await _service.Context.Contents
            .Where(e => e.Id == id)
            .WhereNotDeleted()
            .FirstOrDefaultAsync();

        if (content != null)
        {
            content.Attachments = await _service.Context.Attachments
                .Where(e => e.ContentId == id)
                .WhereNotDeleted()
                .ToListAsync();
        }

        return content;
    }

    public Task<int> AddAsync(Content entity)
    {
        return _validation.AddAsync(entity);
    }

    public Task<int> UpdateAsync(Content entity)
    {
        return _validation.UpdateAsync(entity);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在在我的配置文件中,我可以运行该文件,但是如果我有另一项服务,并且我有大约20个,我不想为每个服务都键入此文件。

container.Register<IEntityBaseService<Content>, EntityBaseService<Content>>();
container.Register<IValidationService<Content>, ValidationService<Content>>();
container.Register<IValidator<Content>, ContentValidator>();

container.Register<IContentService, ContentService>();
Run Code Online (Sandbox Code Playgroud)

所以我在网上看了一下,我认为我可以使用RegisterManyForOpenGeneric方法而不是注册IEntityBaseService和IValidatioNService,但我无法正常工作。我写了

container.RegisterManyForOpenGeneric(typeof(IEntityBaseService<>), typeof(IEntityBaseService<>).Assembly);
container.RegisterManyForOpenGeneric(typeof(IValidationService<>), typeof(IValidationService<>).Assembly);
Run Code Online (Sandbox Code Playgroud)

我得到一个错误的说法

ContentService类型的构造函数包含名称为“ service”且未注册的IEntityBaseService类型的参数。请确保IEntityBaseService已在容器中注册,或更改ContentService的构造函数。

也许我没有正确设置我的实体,所以仅举几例,这是此示例的基本实体

public interface IEntityBase
{
    long Id { get; set; }
}

public abstract class EntityBase : IEntityBase
{
    public long Id { get; set; }
}

public class Content : EntityBase, IAudit
{
    public short Position { get; set; }

    public Content() 
    {
        Position = 1;
    }

}
Run Code Online (Sandbox Code Playgroud)

任何对简单注射器和代码的帮助都值得赞赏

Iai*_*way 5

您使用了错误的注册方法。

RegisterManyForOpenGeneric 存在以支持以下情况:-

container.Register<IValidate<Customer>, CustomerValidator>();
container.Register<IValidate<Employee>, EmployeeValidator>();
container.Register<IValidate<Order>, OrderValidator>();
container.Register<IValidate<Product>, ProductValidator>();

// can replace the above with the following:-
container.RegisterManyForOpenGeneric(
  typeof(IValidate<>),
  typeof(IValidate<>).Assembly);
Run Code Online (Sandbox Code Playgroud)

默认情况下,RegisterManyForOpenGeneric在提供的程序集中搜索实现[specified opengeneric]接口的所有类型,并通过其特定的(封闭的通用)接口注册每种类型。[强调我的]

注意具体类型本身不是通用的(即CustomerValidator实现封闭的通用接口IValidate<Customer>)。这对您而言效果很好,ContentValidator但对实现诸如EntityBaseService<Content>and和.NET这样的开放式通用接口的开放式通用类却不利ValidationService<Content>

您正在寻找:-

container.RegisterOpenGeneric(
  typeof(IEntityBaseService<>),
  typeof(EntityBaseService<>));
Run Code Online (Sandbox Code Playgroud)