简体   繁体   English

向Autofac注册通用接口和类

[英]Registering Generic Interfaces and classes with Autofac

My current Autofac config is working to resolve my ApiControllers in a WebApi. 我当前的Autofac配置正在解决WebApi中的ApiController。

Where I'm struggling is, I'm attempting to create a 'BaseApiController' with generic constructor parameters, but getting exception: 我正在努力的地方是,尝试创建具有通用构造函数参数的“ BaseApiController”,但遇到异常:

No constructors on type 'Service`1[WorldRegion]' can be found with the constructor finder 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'. 使用构造函数查找器“ Autofac.Core.Activators.Reflection.DefaultConstructorFinder”找不到“ Service`1 [WorldRegion]”类型的构造函数。

Here is the code structure: 这是代码结构:

public interface IEntityKey { }
public class WorldRegion : IEntityKey { }
public interface IRepository<T> where T : IEntityKey { }
public interface IService<T> where T : IEntityKey { }
public abstract class Service<T> : IService<T> where T : IEntityKey { }
public interface IWorldRegionService : IService<WorldRegion> { }
public class WorldRegionService : Service<WorldRegion>, IWorldRegionService
{
    private readonly IRepository<WorldRegion> _repository;
}

WORKING API Controller: 工作API控制器:

public class WorldRegionsController : BaseApiController
{
    private readonly IWorldRegionService _worldRegionService;
    private readonly ICultureService _cultureService;

    public WorldRegionsController(IWorldRegionService worldRegionService, ICultureService cultureService)
    {
        _worldRegionService = worldRegionService;
        _cultureService = cultureService;
    }
}

WORKING Autofac config: 工作的Autofac配置:

public static void Register(HttpConfiguration config, IAppBuilder app)
{
    var builder = new ContainerBuilder();
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

    RegisterTypes(builder);

    var container = builder.Build();
    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

    app.UseAutofacMiddleware(container);
    app.UseAutofacWebApi(config);
}

public static void RegisterTypes(ContainerBuilder builder)
{
    // Context
    builder.RegisterType<DataContext>().As<IDataContext>().InstancePerRequest();
    // UOW
    builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
    // Repositories
    builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerRequest();
    // Services
    builder.RegisterType<CultureService>().As<ICultureService>().InstancePerRequest();
    builder.RegisterType<WorldRegionService>().As<IWorldRegionService>().InstancePerRequest();
}

Here is the generic ATTEMPT: 这是通用的ATTEMPT:

// BaseApiController
public abstract class BaseApiController<T> : ApiController where T : IEntityKey

{
    protected readonly IService<T> _service;
    protected readonly ICultureService _cultureService;
    public BaseApiController(IService<T> service, ICultureService cultureService)
    {
        _service = service;
        _cultureService = cultureService;
    }
}

// ApiController
public class WorldRegionsController : BaseApiController<WorldRegion>
{
    public WorldRegionsController(
        IService<WorldRegion> service, ICultureService cultureService)
            : base(service, cultureService) {}
}

// Added to Autofac config
builder.RegisterGeneric(typeof(Service<>)).As(typeof(IService<>)).InstancePerRequest();
// Removed
builder.RegisterType<WorldRegionService>().As<IWorldRegionService>().InstancePerRequest();

With this change, I'm getting the exception message noted above (in yellow). 进行此更改后,我得到了上面指出的异常消息(黄色)。 I think I'm missing something in the Autofac config, just not sure what. 我想我在Autofac配置中丢失了一些东西,只是不确定什么。 Maybe include/register/add 'WorldRegion' somehow. 也许以某种方式包含/注册/添加“ WorldRegion”。

How should I register my types ? 我应该如何注册我的类型?

Your controller expect a IService<WorldRegion> . 您的控制器需要IService<WorldRegion> Autofac find the following registration for this service : Autofac找到此服务的以下注册:

builder.RegisterGeneric(typeof(Service<>)).As(typeof(IService<>)).InstancePerRequest();

So it tries to create a Service<WorldRegion> which is not possible because Service<T> is an abstract class. 因此它尝试创建Service<WorldRegion> ,这是不可能的,因为Service<T>是抽象类。

Don't forget that a IWorldRegionService is a IService<WorldRegion> but a IService<WorldRegion> is not a IWorldRegionService . 不要忘记IWorldRegionServiceIService<WorldRegion>IService<WorldRegion>不是IWorldRegionService

You don't want to register a generic service but want to register all children as a IService<T> , you can do this by using the RegisterAssemblyTypes method with the AsClosedTypedOf 您不想注册通用服务,而是要将所有子级都注册为IService<T> ,则可以通过将RegisterAssemblyTypes方法与AsClosedTypedOf一起使用来AsClosedTypedOf

builder.RegisterAssemblyTypes(this.GetAssemblies())
       .AsClosedTypesOf(typeof(IService<>));

Read Autofac documentation - Assembly scanning for more information and how to properly implement the GetAssemblies method in IIS. 阅读Autofac文档-程序集扫描以获取更多信息以及如何在IIS中正确实现GetAssemblies方法。

At first, I tried removing the abstract from Service<T> , that didn't work, same error. 首先,我尝试从Service<T>删除摘要,该摘要无效,出现相同的错误。 Then I read the Autofac docs and searched around, and I found something similar to Cyril's answer that works: 然后,我阅读了Autofac文档并进行了搜索,发现与Cyril的答案类似的方法有效:

builder.RegisterAssemblyTypes(typeof(Service<>).Assembly)
       .Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces();

I tried Cyril's implementation of builder.RegisterAssemblyTypes() but this.GetAssemblies() wasn't available. 我尝试了Cyril的builder.RegisterAssemblyTypes()的实现,但是this.GetAssemblies()不可用。 I had to use the full path and this also works: 我必须使用完整路径,这也可以:

builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
       .AsClosedTypesOf(typeof(IService<>));

To note, using either builder.RegisterTypes() , the Service<T> can still be abstract. 注意,使用builder.RegisterTypes()Service<T>仍然可以是抽象的。 And just to test, I changed WorldRegionService to abstract, and that DID NOT work. 为了测试,我将WorldRegionService更改为abstract,但DID不起作用。

// THIS DOES NOT WORK..!!!! Must remove 'abstract' from this class.
public abstract class WorldRegionService {}

So both above builder.RegisterTypes() work. 因此,以上builder.RegisterTypes()起作用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM