具有通用接口和组成的简单注入器-不注册接口 [英] Simple Injector with Generic interfaces and composition - Not registering interfaces

查看:45
本文介绍了具有通用接口和组成的简单注入器-不注册接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从继承转向合成,如您在此处所见 https://stackoverflow.com/questions/29653153/composition-migrating-from-heritance

I am moving from inheritance to compositon, as you can see from here https://stackoverflow.com/questions/29653153/composition-migrating-from-inheritance

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

Now i have got it all working, but simple injector wants me to manually register each interface with each type being passed in. Here is the striped down code.

我有IBaseEntityService,它由BaseEntityService实现,

I have IBaseEntityService, which BaseEntityService implements, like so

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();
    }
}

现在我有一个IValidationService,并且ValidationService像这样实现了

Now i have a IValidationService and ValidationService implements that, like so

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);
    }
}

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

Now i can use services, and pass in each interface. So i have a IContentService and ContentService which implements that. This service uses both IEntityBaseService and 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);
    }
}

现在在我的配置文件中,它可以正常工作,但是如果我有另一项服务,并且我有大约20种服务,我不想为每个服务都键入此内容.

Now in my config file, i have this, which works, but if i have another service, and i have about 20 of them, i do not want to type this out for each one.

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

container.Register<IContentService, ContentService>();

所以我在网上看了一下,我认为我可以使用RegisterManyForOpenGeneric方法代替注册IEntityBaseService和IValidatioNService,但我却无法正常工作.我写了

So i looked online and i think i can use the RegisterManyForOpenGeneric method instead of registering IEntityBaseService and IValidatioNService, but i cannot get it too work. I have wrote

container.RegisterManyForOpenGeneric(typeof(IEntityBaseService<>), typeof(IEntityBaseService<>).Assembly);
container.RegisterManyForOpenGeneric(typeof(IValidationService<>), typeof(IValidationService<>).Assembly);

我得到一个错误提示

ContentService类型的构造函数包含类型的参数IEntityBaseService的名称"service"不是挂号的.请确保IEntityBaseService已在中注册容器,或更改ContentService的构造函数.

The constructor of type ContentService contains the parameter of type IEntityBaseService with name 'service' that is not registered. Please ensure IEntityBaseService is registered in the container, or change the constructor of ContentService.

也许我设置的实体不正确,所以请覆盖一下,这是此示例的基本实体

Maybe i have set up my entities incorrectly, so just encase, here are the basic entities for this example

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;
    }

}

对简单的注入器和一般代码的任何帮助

Any help much appreciated on both simple injector and the code in general

推荐答案

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

You're using the wrong registration method.

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

RegisterManyForOpenGeneric exists to support the following scenario:-

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);

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

请注意具体类型本身不是通用的(即 CustomerValidator 实现封闭的通用接口 IValidate< Customer> ).这对于您的 ContentValidator 效果很好,但对于实现诸如 EntityBaseService< Content> ValidationService< Content> 等开放式通用接口的开放式通用类却没有好处.

Note how the concrete types aren't themselves generic (i.e. CustomerValidator implements the closed generic interface IValidate<Customer>). This works fine for your ContentValidator but is no good for open generic classes implementing open generic interfaces like your EntityBaseService<Content> and ValidationService<Content>.

您正在寻找:-

container.RegisterOpenGeneric(
  typeof(IEntityBaseService<>),
  typeof(EntityBaseService<>));

这篇关于具有通用接口和组成的简单注入器-不注册接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆