使用Autofac注册通用接口和类

3

我的当前Autofac配置可以解析WebApi中的ApiControllers。

但是我遇到了困难,我正在尝试创建一个带有通用构造函数参数的“BaseApiController”,但是出现了异常:

在类型“Service`1[WorldRegion]”上找不到任何构造函数,使用构造函数查找器“Autofac.Core.Activators.Reflection.DefaultConstructorFinder”。

以下是代码结构:

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

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

以下是通用的尝试:

// 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”。

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


1
您正在注册 RegisterGeneric(typeof(Service<>)).As(typeof(IService<>)),但是 Service<T> 本身是抽象的,因此 Autofac 无法创建它。 - Steven
2个回答

5
您的控制器需要一个 IService<WorldRegion>Autofac 找到了以下关于此服务的注册信息:
builder.RegisterGeneric(typeof(Service<>)).As(typeof(IService<>)).InstancePerRequest();

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

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

如果您不想注册通用服务,而是想将所有子项注册为IService<T>,则可以使用RegisterAssemblyTypes方法和AsClosedTypedOf来实现。

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

阅读Autofac文档 - 程序集扫描获取更多信息以及如何在IIS中正确实现GetAssemblies方法。


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仍然可以是抽象的。为了测试,我将WorldRegionService更改为抽象类,但这并没有起作用。
// THIS DOES NOT WORK..!!!! Must remove 'abstract' from this class.
public abstract class WorldRegionService {}

所以上述两个builder.RegisterTypes()都可以工作。


1
请使用问题上的编辑链接添加更多信息。Post Answer按钮仅用于完整回答问题。 - Koby Douek
抱歉,我不明白你的意思。我很少发布问题,所以不熟悉协议。但是我发布的是对Cyril帖子的回复,并确认了什么有效和什么无效。这是最终和完整的答案。 - Ronnie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接