使用Autofac注册通用接口和类

时间:2017-03-22 05:51:18

标签: c# asp.net-web-api dependency-injection autofac

我当前的Autofac配置正在解决WebApi中的ApiControllers。

我正在努力的是,我正在尝试使用通用构造函数参数创建一个'BaseApiController',但是获得异常:

  

可以使用构造函数查找器'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'找到类型'Service`1 [WorldRegion]'上的构造函数。

以下是代码结构:

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控制器:

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

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

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

这是通用的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();

通过此更改,我收到上面提到的异常消息(黄色)。我想我在Autofac配置中遗漏了一些东西,只是不确定是什么。也许以某种方式包括/注册/添加'WorldRegion'。

我应该如何注册我的类型?

2 个答案:

答案 0 :(得分:0)

您的控制器需要IService<WorldRegion> Autofac 找到此服务的以下注册:

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

因此它尝试创建一个Service<WorldRegion>,这是不可能的,因为Service<T>是一个抽象类。

不要忘记,IWorldRegionServiceIService<WorldRegion>,但IService<WorldRegion>不是IWorldRegionService

您不想注册通用服务,但希望将所有子项注册为IService<T>,您可以使用RegisterAssemblyTypes AsClosedTypedOf方法执行此操作>

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

阅读Autofac documentation - Assembly scanning以获取更多信息以及如何在IIS中正确实施GetAssemblies方法。

答案 1 :(得分:0)

首先,我尝试从Service<T>删除不起作用的摘要,同样的错误。然后我阅读了Autofac文档并搜索了一下,我找到了与Cyril's answer类似的东西:

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

我尝试了Cyril的builder.RegisterAssemblyTypes()实现,但this.GetAssemblies()无效。我必须使用完整路径,这也有效:

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

要注意,使用builder.RegisterTypes()Service<T>仍然可以是抽象的。只是为了测试,我将WorldRegionService更改为abstract,并且DID不起作用。

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

因此builder.RegisterTypes()以上都有效。