这是使用Autofac.Extensions.DependencyInjection的解决方案。如果要求超出提供的容器的功能,Microsoft 建议使用另一个容器。
内置服务容器旨在满足框架和大多数消费者应用程序的需求。我们建议使用内置容器,除非您需要它不支持的特定功能。
回答这个问题的设置包括创建一些仅用于说明的类型。我试图将其保持在最低限度。
我们拥有的是:
- 两种都依赖的类型
IDependency
- 的两种实现
IDependency
- 我们希望将不同的实现注入
IDependency
到需要它的每种类型中。
- 注入的两个类
IDependency
都将其作为属性公开。这样我们就可以测试该解决方案是否有效。(我不会在“真实”代码中这样做。这只是为了说明和测试。)
public interface INeedsDependency
{
IDependency InjectedDependency { get; }
}
public class NeedsDependency : INeedsDependency
{
private readonly IDependency _dependency;
public NeedsDependency(IDependency dependency)
{
_dependency = dependency;
}
public IDependency InjectedDependency => _dependency;
}
public interface IAlsoNeedsDependency
{
IDependency InjectedDependency { get; }
}
public class AlsoNeedsDependency : IAlsoNeedsDependency
{
private readonly IDependency _dependency;
public AlsoNeedsDependency(IDependency dependency)
{
_dependency = dependency;
}
public IDependency InjectedDependency => _dependency;
}
public interface IDependency { }
public class DependencyVersionOne : IDependency { }
public class DependencyVersionTwo : IDependency { }
我们如何配置它以便NeedsDependency
获取DependencyVersionOne
和AlsoNeedsDependency
获取DependencyVersionTwo
?
这里是单元测试的形式。以这种方式编写它可以很容易地验证我们是否得到了我们期望的结果。
[TestClass]
public class TestNamedDependencies
{
[TestMethod]
public void DifferentClassesGetDifferentDependencies()
{
var services = new ServiceCollection();
var serviceProvider = GetServiceProvider(services);
var needsDependency = serviceProvider.GetService<INeedsDependency>();
Assert.IsInstanceOfType(needsDependency.InjectedDependency, typeof(DependencyVersionOne));
var alsoNeedsDependency = serviceProvider.GetService<IAlsoNeedsDependency>();
Assert.IsInstanceOfType(alsoNeedsDependency.InjectedDependency, typeof(DependencyVersionTwo));
}
private IServiceProvider GetServiceProvider(IServiceCollection services)
{
/*
* With Autofac, ContainerBuilder and Container are similar to
* IServiceCollection and IServiceProvider.
* We register services with the ContainerBuilder and then
* use it to create a Container.
*/
var builder = new ContainerBuilder();
/*
* This is important. If we already had services registered with the
* IServiceCollection, they will get added to the new container.
*/
builder.Populate(services);
/*
* Register two implementations of IDependency.
* Give them names.
*/
builder.RegisterType<DependencyVersionOne>().As<IDependency>()
.Named<IDependency>("VersionOne")
.SingleInstance();
builder.RegisterType<DependencyVersionTwo>().As<IDependency>()
.Named<IDependency>("VersionTwo")
.SingleInstance();
/*
* Register the classes that depend on IDependency.
* Specify the name to use for each one.
* In the future, if we want to change which implementation
* is used, we just change the name.
*/
builder.Register(ctx => new NeedsDependency(ctx.ResolveNamed<IDependency>("VersionOne")))
.As<INeedsDependency>();
builder.Register(ctx => new AlsoNeedsDependency(ctx.ResolveNamed<IDependency>("VersionTwo")))
.As<IAlsoNeedsDependency>();
// Build the container
var container = builder.Build();
/*
* This last step uses the Container to create an AutofacServiceProvider,
* which is an implementation of IServiceProvider. This is the IServiceProvider
* our app will use to resolve dependencies.
*/
return new AutofacServiceProvider(container);
}
}
单元测试解析这两种类型并验证我们是否注入了我们期望的内容。
现在,我们如何将其放入“真实”应用程序中?
在你的Startup
课堂上,改变
public void ConfigureServices(IServiceCollection services)
至
public IServiceProvider ConfigureServices(IServiceCollection services)
现在ConfigureServices
将返回一个IServiceProvider
.
然后,您可以将 AutofacContainerBuilder
步骤添加到ConfigureServices
并让方法返回new AutofacServiceProvider(container);
如果您已经在 注册服务IServiceCollection
,那很好。保持原样。无论您需要向 Autofac 注册什么服务,都请ContainerBuilder
注册这些服务。
只需确保包含此步骤:
builder.Populate(services);
这样在 . 注册的任何内容IServiceCollection
也会添加到ContainerBuilder
.
这可能看起来有点令人费解,而不是仅仅使用提供的 IoC 容器来工作。好处是一旦你克服了这个困难,你就可以利用其他容器可以做的有用的事情。您甚至可能决定使用 Autofac 来注册所有依赖项。您可以搜索使用 Autofac 注册和使用命名或键控依赖项的不同方法,所有这些选项都可供您使用。(他们的文档很棒。)您也可以使用Windsor或其他人。
依赖注入早在Microsoft.Extensions.DependencyInjection
,IServiceCollection
和IServiceProvider
. 它有助于学习如何使用不同的工具做相同或相似的事情,以便我们使用底层概念,而不仅仅是特定的实现。
这是Autofac的更多文档,专门用于将其与 ASP.NET Core 一起使用。