我正在使用.Net 4.5,ASP.NET MVC 5和NuGet包:自动 3.5.2Autofac ASP.NET Web API 5 Integration 3.0.0-rc1
我有一个接口的 2 种不同的实现:
public class MemoryStreamService : IStreamService { ... }
public class HttpStreamService : IStreamService { ... }
还有另一个通过构造函数注入使用接口的具体类:
public class MainService : IMainService
{
public MainService(IStreamService streamService) { ... }
}
我有 2 个 ASP.NET Web API 控制器,通过构造函数注入使用主服务:
public class MemoryStreamController : ApiController
{
public MemoryStreamController(IMainService mainService) { ... }
}
public class HttpStreamController : ApiController
{
public HttpStreamController(IMainService mainService) { ... }
}
我想要的是当IStreamService的实例需要在调用MemoryStreamController的上下文中实例化时使用MemoryStreamService实现,当我们在调用HttpStreamController的上下文中时,使用HttpStreamService实现。
我试图通过在 Global.asax 的 Application_Start(( 的 Autofac 生成器中注册控制器和服务类来实现这一点.cs
方式如下:builder.RegisterType<MainService>().As<IMainService>();
builder.RegisterType<MemoryStreamService>()
.As<IStreamService>()
.InstancePerApiControllerType(typeof(MemoryStreamController));
builder.RegisterType<HttpStreamService>()
.As<IStreamService>()
.InstancePerApiControllerType(typeof(HttpStreamController));
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
但看起来 InstancePerApiControllerType(( 不适用于此:对于两个控制器,我总是获得 IStreamService 的第一个注册实现类型(在本示例中为 MemoryStreamController(。
我需要如何配置 Autofac 以便在 MemoryStreamController 处理的请求上下文中获取 MemoryStreamService 实例,以及为 HttpStreamController 发起的调用配置 HttpStreamService 实例?
编辑:如果我没有对控制器使用依赖注入,我会这样做:
public class MemoryStreamController : ApiController
{
public MemoryStreamController()
{
this.mainService = new MainService(new MemoryStreamService());
}
}
public class HttpStreamController : ApiController
{
public HttpStreamController()
{
this.mainService = new MainService(new HttpStreamService());
}
}
所以我的问题可以理解为:如何使用 Autofac 注册我的控制器和所有服务来实现相同的目标?
怎么样。首先,将服务注册为:
builder.RegisterType<MemoryStreamService>()
.Named<IStreamService>("MemoryStreamService")
.InstancePerApiControllerType(typeof(MemoryStreamController));
builder.RegisterType<HttpStreamService>()
.Named<IStreamService>("HttpStreamService")
.InstancePerApiControllerType(typeof(HttpStreamController));
然后注册一个 func 工厂,该工厂可以根据名称解析正确的服务。喜欢这个:
builder.Register<Func<string, IStreamService>>(c =>
{
var context = c.Resolve<IComponentContext>();
return service =>
{
return context.ResolveNamed<IStreamService>(service);
};
});
然后在控制器中解析IMainService
时,可以注入Func<string, IMainService>
(MainService
构造函数中的第一个参数必须是字符串(。这样,您可以传递要解析的服务的名称。喜欢这个:
public class MemoryStreamController : ApiController
{
private IMainService _service;
public MemoryStreamController(Func<string, IMainService> mainService)
{
_service = mainService("MemoryStreamService")
}
}
然后在 MainService
的构造函数中,使用注入的类型名称调用 func 工厂。喜欢这个:
public MainService(string type, Func<string, IStreamService> factory)
{
_service = factory(type);
}
我遵循了@TravisIllig建议(谢谢!(并且:
1( 对两个"流服务"都使用命名注册,
2( 为 MainService 使用了 2 个命名注册,它们在可以作为参数
的流服务类型上有所不同3( 通过根据需要指定每个命名的主服务来注册控制器。
builder.RegisterType<MemoryStreamService>().Named<IStreamService>("memoryService");
builder.RegisterType<HttpStreamService>().Named<IStreamService>("httpService");
builder
.RegisterType<MainService>()
.As<IMainService>()
.WithParameter(ResolvedParameter.ForNamed<IStreamService>("memoryService"))
.Named<IMainService>("mainServiceForMemoryStreams");
builder
.RegisterType<MainService>()
.As<IMainService>()
.WithParameter(ResolvedParameter.ForNamed<IStreamService>("httpService"))
.Named<IMainService>("mainServiceForHttpStreams");
// This is for registering the other controllers of my API
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Manually registers controllers that need an specific instance of IStreamService.
// These registrations needs to be placed after the "RegisterApiControllers()" call in order to Autofac to perform the desired injections.
builder.RegisterType<MemoryStreamController>()
.WithParameter(ResolvedParameter.ForNamed<IMainService>("mainServiceForMemoryStreams"));
builder.RegisterType<HttpStreamController>()
.WithParameter(ResolvedParameter.ForNamed<IMainService>("mainServiceForHttpStreams"));